diff options
author | Martin Basti <mbasti@redhat.com> | 2015-05-22 17:38:16 +0200 |
---|---|---|
committer | Jan Cholasta <jcholast@redhat.com> | 2015-05-25 16:34:44 +0000 |
commit | 027515230a93a7a60983d3eca26a97a0d9c3610e (patch) | |
tree | cf3e0356373d5dde1711a64e47035c06aaaf12fd /install | |
parent | 6a4b428120c2e351ad0f1b4573f50b106844b1fd (diff) | |
download | freeipa-027515230a93a7a60983d3eca26a97a0d9c3610e.tar.gz freeipa-027515230a93a7a60983d3eca26a97a0d9c3610e.tar.xz freeipa-027515230a93a7a60983d3eca26a97a0d9c3610e.zip |
Server Upgrade: Move code from ipa-upgradeconfig to separate module
This also prevent the script ipa-upgradeconfig execute upgrading.
Upgrade of services is called from ipa-server-upgrade
https://fedorahosted.org/freeipa/ticket/4904
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Diffstat (limited to 'install')
-rwxr-xr-x | install/tools/ipa-upgradeconfig | 1412 |
1 files changed, 2 insertions, 1410 deletions
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig index dfef1e0aa..43292966a 100755 --- a/install/tools/ipa-upgradeconfig +++ b/install/tools/ipa-upgradeconfig @@ -19,1417 +19,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -""" -Upgrade configuration files to a newer template. -""" - import sys -import re -import os -import shutil -import pwd -import fileinput -import ConfigParser -import grp - -from ipalib import api -import SSSDConfig -import ipalib.util -import ipalib.errors -from ipaplatform import services -from ipaplatform.tasks import tasks -from ipapython import ipautil, sysrestore, version, certdb -from ipapython.config import IPAOptionParser -from ipapython.ipa_log_manager import * -from ipapython import certmonger -from ipapython import dogtag -from ipaplatform.paths import paths -from ipaserver.install import installutils -from ipaserver.install import dsinstance -from ipaserver.install import httpinstance -from ipaserver.install import memcacheinstance -from ipaserver.install import bindinstance -from ipaserver.install import service -from ipaserver.install import cainstance -from ipaserver.install import certs -from ipaserver.install import otpdinstance -from ipaserver.install import sysupgrade -from ipaserver.install import dnskeysyncinstance - - -def parse_options(): - parser = IPAOptionParser(version=version.VERSION) - parser.add_option("-d", "--debug", dest="debug", action="store_true", - default=False, help="print debugging information") - parser.add_option("-q", "--quiet", dest="quiet", - action="store_true", - default=False, help="Output only errors") - - options, args = parser.parse_args() - safe_options = parser.get_safe_opts(options) - - return safe_options, options - -class KpasswdInstance(service.SimpleServiceInstance): - def __init__(self): - service.SimpleServiceInstance.__init__(self, "ipa_kpasswd") - -def uninstall_ipa_kpasswd(): - """ - We can't use the full service uninstaller because that will attempt - to stop and disable the service which by now doesn't exist. We just - want to clean up sysrestore.state to remove all references to - ipa_kpasswd. - """ - ipa_kpasswd = KpasswdInstance() - - running = ipa_kpasswd.restore_state("running") - enabled = not ipa_kpasswd.restore_state("enabled") - - if enabled is not None and not enabled: - ipa_kpasswd.remove() - -def backup_file(filename, ext): - """Make a backup of filename using ext as the extension. Do not overwrite - previous backups.""" - if not os.path.isabs(filename): - raise ValueError("Absolute path required") - - backupfile = filename + ".bak" - (reldir, file) = os.path.split(filename) - - while os.path.exists(backupfile): - backupfile = backupfile + "." + str(ext) - - try: - shutil.copy2(filename, backupfile) - except IOError, e: - if e.errno == 2: # No such file or directory - pass - else: - raise e - -def update_conf(sub_dict, filename, template_filename): - template = ipautil.template_file(template_filename, sub_dict) - fd = open(filename, "w") - fd.write(template) - fd.close() - -def find_hostname(): - """Find the hostname currently configured in ipa-rewrite.conf""" - filename=paths.HTTPD_IPA_REWRITE_CONF - - if not ipautil.file_exists(filename): - return None - - pattern = "^[\s#]*.*https:\/\/([A-Za-z0-9\.\-]*)\/.*" - p = re.compile(pattern) - for line in fileinput.input(filename): - if p.search(line): - fileinput.close() - return p.search(line).group(1) - fileinput.close() - - raise RuntimeError("Unable to determine the fully qualified hostname from %s" % filename) - -def find_autoredirect(fqdn): - """ - When upgrading ipa-rewrite.conf we need to see if the automatic redirect - was disabled during install time (or afterward). So sift through the - configuration file and see if we can determine the status. - - Returns True if autoredirect is enabled, False otherwise - """ - filename = paths.HTTPD_IPA_REWRITE_CONF - if os.path.exists(filename): - pattern = "^RewriteRule \^/\$ https://%s/ipa/ui \[L,NC,R=301\]" % fqdn - p = re.compile(pattern) - for line in fileinput.input(filename): - if p.search(line): - fileinput.close() - return True - fileinput.close() - return False - return True - -def find_version(filename): - """Find the version of a configuration file - - If no VERSION entry exists in the file, returns 0. - If the file does not exist, returns -1. - """ - if os.path.exists(filename): - pattern = "^[\s#]*VERSION\s+([0-9]+)\s+.*" - p = re.compile(pattern) - for line in fileinput.input(filename): - if p.search(line): - fileinput.close() - return p.search(line).group(1) - fileinput.close() - - # no VERSION found - return 0 - else: - return -1 - -def upgrade(sub_dict, filename, template, add=False): - """ - Get the version from the current and template files and update the - installed configuration file if there is a new template. - - If add is True then create a new configuration file. - """ - old = int(find_version(filename)) - new = int(find_version(template)) - - if old < 0 and not add: - root_logger.error("%s not found." % filename) - sys.exit(1) - - if new < 0: - root_logger.error("%s not found." % template) - - if old == 0: - # The original file does not have a VERSION entry. This means it's now - # managed by IPA, but previously was not. - root_logger.warning("%s is now managed by IPA. It will be " - "overwritten. A backup of the original will be made.", filename) - - if old < new or (add and old == 0): - backup_file(filename, new) - update_conf(sub_dict, filename, template) - root_logger.info("Upgraded %s to version %d", filename, new) - -def check_certs(): - """Check ca.crt is in the right place, and try to fix if not""" - root_logger.info('[Verifying that root certificate is published]') - if not os.path.exists(paths.CA_CRT): - ca_file = paths.ALIAS_CACERT_ASC - if os.path.exists(ca_file): - old_umask = os.umask(022) # make sure its readable by httpd - try: - shutil.copyfile(ca_file, paths.CA_CRT) - finally: - os.umask(old_umask) - else: - root_logger.error("Missing Certification Authority file.") - root_logger.error("You should place a copy of the CA certificate in /usr/share/ipa/html/ca.crt") - else: - root_logger.debug('Certificate file exists') - -def upgrade_pki(ca, fstore): - """ - Update/add the dogtag proxy configuration. The IPA side of this is - handled in ipa-pki-proxy.conf. - - This requires enabling SSL renegotiation. - """ - configured_constants = dogtag.configured_constants() - root_logger.info('[Verifying that CA proxy configuration is correct]') - if not ca.is_configured(): - root_logger.info('CA is not configured') - return - - http = httpinstance.HTTPInstance(fstore) - http.enable_mod_nss_renegotiate() - if not installutils.get_directive(configured_constants.CS_CFG_PATH, - 'proxy.securePort', '=') and \ - os.path.exists(paths.PKI_SETUP_PROXY): - # update proxy configuration with stopped dogtag to prevent corruption - # of CS.cfg - ipautil.run([paths.PKI_SETUP_PROXY, '-pki_instance_root=/var/lib', - '-pki_instance_name=pki-ca','-subsystem_type=ca']) - root_logger.debug('Proxy configuration updated') - else: - root_logger.debug('Proxy configuration up-to-date') - -def update_dbmodules(realm, filename=paths.KRB5_CONF): - newfile = [] - found_dbrealm = False - found_realm = False - prefix = '' - - root_logger.info('[Verifying that KDC configuration is using ipa-kdb backend]') - st = os.stat(filename) - fd = open(filename) - - lines = fd.readlines() - fd.close() - - if ' db_library = ipadb.so\n' in lines: - root_logger.debug('dbmodules already updated in %s', filename) - return - - for line in lines: - if line.startswith('[dbmodules]'): - found_dbrealm = True - if found_dbrealm and line.find(realm) > -1: - found_realm = True - prefix = '#' - if found_dbrealm and line.find('}') > -1 and found_realm: - found_realm = False - newfile.append('#%s' % line) - prefix = '' - continue - - newfile.append('%s%s' % (prefix, line)) - - # Append updated dbmodules information - newfile.append(' %s = {\n' % realm) - newfile.append(' db_library = ipadb.so\n') - newfile.append(' }\n') - - # Write out new file - fd = open(filename, 'w') - fd.write("".join(newfile)) - fd.close() - root_logger.debug('%s updated', filename) - -def cleanup_kdc(fstore): - """ - Clean up old KDC files if they exist. We need to remove the actual - file and any references in the uninstall configuration. - """ - root_logger.info('[Checking for deprecated KDC configuration files]') - for file in ['kpasswd.keytab', 'ldappwd']: - filename = os.path.join(paths.VAR_KERBEROS_KRB5KDC_DIR, file) - installutils.remove_file(filename) - if fstore.has_file(filename): - fstore.untrack_file(filename) - root_logger.debug('Uninstalling %s', filename) - -def cleanup_adtrust(fstore): - """ - Clean up any old Samba backup files that were deprecated. - """ - - root_logger.info('[Checking for deprecated backups of Samba ' - 'configuration files]') - - for backed_up_file in [paths.SMB_CONF]: - if fstore.has_file(backed_up_file): - fstore.untrack_file(backed_up_file) - root_logger.debug('Removing %s from backup', backed_up_file) - - -def setup_firefox_extension(fstore): - """Set up the Firefox configuration extension, if it's not set up yet - """ - root_logger.info('[Setting up Firefox extension]') - http = httpinstance.HTTPInstance(fstore) - realm = api.env.realm - domain = api.env.domain - http.setup_firefox_extension(realm, domain) - - -def upgrade_ipa_profile(ca, domain, fqdn): - """ - Update the IPA Profile provided by dogtag - - Returns True if restart is needed, False otherwise. - """ - root_logger.info('[Verifying that CA service certificate profile is updated]') - if ca.is_configured(): - ski = ca.enable_subject_key_identifier() - if ski: - root_logger.debug('Subject Key Identifier updated.') - else: - root_logger.debug('Subject Key Identifier already set.') - san = ca.enable_subject_alternative_name() - if san: - root_logger.debug('Subject Alternative Name updated.') - else: - root_logger.debug('Subject Alternative Name already set.') - audit = ca.set_audit_renewal() - uri = ca.set_crl_ocsp_extensions(domain, fqdn) - if audit or ski or san or uri: - return True - else: - root_logger.info('CA is not configured') - - return False - - -def named_remove_deprecated_options(): - """ - From IPA 3.3, persistent search is a default mechanism for new DNS zone - detection. - - Remove psearch, zone_refresh and cache_ttl options, as they have been - deprecated in bind-dyndb-ldap configuration file. - - When some change in named.conf is done, this functions returns True. - """ - - root_logger.info('[Removing deprecated DNS configuration options]') - - if not bindinstance.named_conf_exists(): - # DNS service may not be configured - root_logger.info('DNS is not configured') - return False - - deprecated_options = ['zone_refresh', 'psearch', 'cache_ttl'] - removed_options = [] - - try: - # Remove all the deprecated options - for option in deprecated_options: - value = bindinstance.named_conf_get_directive(option) - - if value is not None: - bindinstance.named_conf_set_directive(option, None) - removed_options.append(option) - - except IOError, e: - root_logger.error('Cannot modify DNS configuration in %s: %s', - bindinstance.NAMED_CONF, e) - - # Log only the changed options - if not removed_options: - root_logger.debug('No changes made') - return False - - root_logger.debug('The following configuration options have been removed: ' - '{options}'.format(options = ', '.join(removed_options))) - return True - - -def named_set_minimum_connections(): - """ - Sets the minimal number of connections. - - When some change in named.conf is done, this functions returns True. - """ - - changed = False - - root_logger.info('[Ensuring minimal number of connections]') - - if not bindinstance.named_conf_exists(): - # DNS service may not be configured - root_logger.info('DNS is not configured') - return changed - - # make sure number of connections is right - minimum_connections = 4 - - try: - connections = bindinstance.named_conf_get_directive('connections') - except IOError, e: - root_logger.debug('Cannot retrieve connections option from %s: %s', - bindinstance.NAMED_CONF, e) - return changed - - try: - if connections is not None: - connections = int(connections) - except ValueError: - # this should not happend, but there is some bad value in - # "connections" option, bail out - pass - else: - if connections is not None and connections < minimum_connections: - try: - bindinstance.named_conf_set_directive('connections', - minimum_connections) - root_logger.debug('Connections set to %d', minimum_connections) - except IOError, e: - root_logger.error('Cannot update connections in %s: %s', - bindinstance.NAMED_CONF, e) - else: - changed = True - - if not changed: - root_logger.debug('No changes made') - - return changed - - -def named_enable_serial_autoincrement(): - """ - Serial autoincrement is a requirement for zone transfers or DNSSEC. It - should be enabled both for new installs and upgraded servers. - - When some change in named.conf is done, this functions returns True - """ - changed = False - - root_logger.info('[Enabling serial autoincrement in DNS]') - - if not bindinstance.named_conf_exists(): - # DNS service may not be configured - root_logger.info('DNS is not configured') - return changed - - try: - serial_autoincrement = bindinstance.named_conf_get_directive( - 'serial_autoincrement') - except IOError, e: - root_logger.debug('Cannot retrieve psearch option from %s: %s', - bindinstance.NAMED_CONF, e) - return changed - else: - serial_autoincrement = None if serial_autoincrement is None \ - else serial_autoincrement.lower() - - # enable SOA serial autoincrement - if not sysupgrade.get_upgrade_state('named.conf', 'autoincrement_enabled'): - if serial_autoincrement != 'yes': - try: - bindinstance.named_conf_set_directive('serial_autoincrement', 'yes') - except IOError, e: - root_logger.error('Cannot enable serial_autoincrement in %s: %s', - bindinstance.NAMED_CONF, e) - return changed - else: - root_logger.debug('Serial autoincrement enabled') - changed = True - else: - root_logger.debug('Serial autoincrement is alredy enabled') - sysupgrade.set_upgrade_state('named.conf', 'autoincrement_enabled', True) - else: - root_logger.debug('Skip serial autoincrement check') - - return changed - -def named_update_gssapi_configuration(): - """ - Update GSSAPI configuration in named.conf to a recent API. - tkey-gssapi-credential and tkey-domain is replaced with tkey-gssapi-keytab. - Details can be found in https://fedorahosted.org/freeipa/ticket/3429. - - When some change in named.conf is done, this functions returns True - """ - - root_logger.info('[Updating GSSAPI configuration in DNS]') - - if not bindinstance.named_conf_exists(): - # DNS service may not be configured - root_logger.info('DNS is not configured') - return False - - if sysupgrade.get_upgrade_state('named.conf', 'gssapi_updated'): - root_logger.debug('Skip GSSAPI configuration check') - return False - - try: - gssapi_keytab = bindinstance.named_conf_get_directive('tkey-gssapi-keytab', - bindinstance.NAMED_SECTION_OPTIONS) - except IOError, e: - root_logger.error('Cannot retrieve tkey-gssapi-keytab option from %s: %s', - bindinstance.NAMED_CONF, e) - return False - else: - if gssapi_keytab: - root_logger.debug('GSSAPI configuration already updated') - sysupgrade.set_upgrade_state('named.conf', 'gssapi_updated', True) - return False - - try: - tkey_credential = bindinstance.named_conf_get_directive('tkey-gssapi-credential', - bindinstance.NAMED_SECTION_OPTIONS) - tkey_domain = bindinstance.named_conf_get_directive('tkey-domain', - bindinstance.NAMED_SECTION_OPTIONS) - except IOError, e: - root_logger.error('Cannot retrieve tkey-gssapi-credential option from %s: %s', - bindinstance.NAMED_CONF, e) - return False - - if not tkey_credential or not tkey_domain: - root_logger.error('Either tkey-gssapi-credential or tkey-domain is missing in %s. ' - 'Skip update.', bindinstance.NAMED_CONF) - return False - - try: - bindinstance.named_conf_set_directive( - 'tkey-gssapi-credential', None, - bindinstance.NAMED_SECTION_OPTIONS) - bindinstance.named_conf_set_directive( - 'tkey-domain', None, - bindinstance.NAMED_SECTION_OPTIONS) - bindinstance.named_conf_set_directive( - 'tkey-gssapi-keytab', paths.NAMED_KEYTAB, - bindinstance.NAMED_SECTION_OPTIONS) - except IOError, e: - root_logger.error('Cannot update GSSAPI configuration in %s: %s', - bindinstance.NAMED_CONF, e) - return False - else: - root_logger.debug('GSSAPI configuration updated') - - sysupgrade.set_upgrade_state('named.conf', 'gssapi_updated', True) - return True - - -def named_update_pid_file(): - """ - Make sure that named reads the pid file from the right file - """ - root_logger.info('[Updating pid-file configuration in DNS]') - - if not bindinstance.named_conf_exists(): - # DNS service may not be configured - root_logger.info('DNS is not configured') - return False - - if sysupgrade.get_upgrade_state('named.conf', 'pid-file_updated'): - root_logger.debug('Skip pid-file configuration check') - return False - - try: - pid_file = bindinstance.named_conf_get_directive('pid-file', - bindinstance.NAMED_SECTION_OPTIONS) - except IOError, e: - root_logger.error('Cannot retrieve pid-file option from %s: %s', - bindinstance.NAMED_CONF, e) - return False - else: - if pid_file: - root_logger.debug('pid-file configuration already updated') - sysupgrade.set_upgrade_state('named.conf', 'pid-file_updated', True) - return False - - try: - bindinstance.named_conf_set_directive('pid-file', paths.NAMED_PID, - bindinstance.NAMED_SECTION_OPTIONS) - except IOError, e: - root_logger.error('Cannot update pid-file configuration in %s: %s', - bindinstance.NAMED_CONF, e) - return False - else: - root_logger.debug('pid-file configuration updated') - - sysupgrade.set_upgrade_state('named.conf', 'pid-file_updated', True) - return True - -def named_enable_dnssec(): - """ - Enable dnssec in named.conf - """ - if not bindinstance.named_conf_exists(): - # DNS service may not be configured - root_logger.info('DNS is not configured') - return False - - if not sysupgrade.get_upgrade_state('named.conf', 'dnssec_enabled'): - root_logger.info('[Enabling "dnssec-enable" configuration in DNS]') - try: - bindinstance.named_conf_set_directive('dnssec-enable', 'yes', - bindinstance.NAMED_SECTION_OPTIONS, - str_val=False) - except IOError, e: - root_logger.error('Cannot update dnssec-enable configuration in %s: %s', - bindinstance.NAMED_CONF, e) - return False - else: - root_logger.debug('dnssec-enabled in %s' % bindinstance.NAMED_CONF) - - sysupgrade.set_upgrade_state('named.conf', 'dnssec_enabled', True) - return True - -def named_validate_dnssec(): - """ - Disable dnssec validation in named.conf - - We can't let enable it by default, there can be non-valid dns forwarders - which breaks DNSSEC validation - """ - if not bindinstance.named_conf_exists(): - # DNS service may not be configured - root_logger.info('DNS is not configured') - return False - - if (not sysupgrade.get_upgrade_state('named.conf', 'dnssec_validation_upgraded') - and bindinstance.named_conf_get_directive( - 'dnssec-validation', bindinstance.NAMED_SECTION_OPTIONS, - str_val=False) is None): - # dnssec-validation is not configured, disable it - root_logger.info('[Disabling "dnssec-validate" configuration in DNS]') - try: - bindinstance.named_conf_set_directive('dnssec-validation', 'no', - bindinstance.NAMED_SECTION_OPTIONS, - str_val=False) - except IOError, e: - root_logger.error('Cannot update dnssec-validate configuration in %s: %s', - bindinstance.NAMED_CONF, e) - return False - else: - root_logger.debug('dnssec-validate already configured in %s' % bindinstance.NAMED_CONF) - - sysupgrade.set_upgrade_state('named.conf', 'dnssec_validation_upgraded', True) - return True - -def named_bindkey_file_option(): - """ - Add options bindkey_file to named.conf - """ - if not bindinstance.named_conf_exists(): - # DNS service may not be configured - root_logger.info('DNS is not configured') - return False - - if sysupgrade.get_upgrade_state('named.conf', 'bindkey-file_updated'): - root_logger.debug('Skip bindkey-file configuration check') - return False - - try: - bindkey_file = bindinstance.named_conf_get_directive('bindkey-file', - bindinstance.NAMED_SECTION_OPTIONS) - except IOError, e: - root_logger.error('Cannot retrieve bindkey-file option from %s: %s', - bindinstance.NAMED_CONF, e) - return False - else: - if bindkey_file: - root_logger.debug('bindkey-file configuration already updated') - sysupgrade.set_upgrade_state('named.conf', 'bindkey-file_updated', True) - return False - - root_logger.info('[Setting "bindkeys-file" option in named.conf]') - try: - bindinstance.named_conf_set_directive('bindkeys-file', - paths.NAMED_BINDKEYS_FILE, - bindinstance.NAMED_SECTION_OPTIONS) - except IOError, e: - root_logger.error('Cannot update bindkeys-file configuration in %s: %s', - bindinstance.NAMED_CONF, e) - return False - - - sysupgrade.set_upgrade_state('named.conf', 'bindkey-file_updated', True) - return True - -def named_managed_keys_dir_option(): - """ - Add options managed_keys_directory to named.conf - """ - if not bindinstance.named_conf_exists(): - # DNS service may not be configured - root_logger.info('DNS is not configured') - return False - - if sysupgrade.get_upgrade_state('named.conf', 'managed-keys-directory_updated'): - root_logger.debug('Skip managed-keys-directory configuration check') - return False - - try: - managed_keys = bindinstance.named_conf_get_directive('managed-keys-directory', - bindinstance.NAMED_SECTION_OPTIONS) - except IOError, e: - root_logger.error('Cannot retrieve managed-keys-directory option from %s: %s', - bindinstance.NAMED_CONF, e) - return False - else: - if managed_keys: - root_logger.debug('managed_keys_directory configuration already updated') - sysupgrade.set_upgrade_state('named.conf', 'managed-keys-directory_updated', True) - return False - - root_logger.info('[Setting "managed-keys-directory" option in named.conf]') - try: - bindinstance.named_conf_set_directive('managed-keys-directory', - paths.NAMED_MANAGED_KEYS_DIR, - bindinstance.NAMED_SECTION_OPTIONS) - except IOError, e: - root_logger.error('Cannot update managed-keys-directory configuration in %s: %s', - bindinstance.NAMED_CONF, e) - return False - - - sysupgrade.set_upgrade_state('named.conf', 'managed-keys-directory_updated', True) - return True - -def named_root_key_include(): - """ - Add options managed_keys_directory to named.conf - """ - if not bindinstance.named_conf_exists(): - # DNS service may not be configured - root_logger.info('DNS is not configured') - return False - - if sysupgrade.get_upgrade_state('named.conf', 'root_key_updated'): - root_logger.debug('Skip root key configuration check') - return False - - try: - root_key = bindinstance.named_conf_include_exists(paths.NAMED_ROOT_KEY) - except IOError, e: - root_logger.error('Cannot check root key include in %s: %s', - bindinstance.NAMED_CONF, e) - return False - else: - if root_key: - root_logger.debug('root keys configuration already updated') - sysupgrade.set_upgrade_state('named.conf', 'root_key_updated', True) - return False - - root_logger.info('[Including named root key in named.conf]') - try: - bindinstance.named_conf_add_include(paths.NAMED_ROOT_KEY) - except IOError, e: - root_logger.error('Cannot update named root key include in %s: %s', - bindinstance.NAMED_CONF, e) - return False - - - sysupgrade.set_upgrade_state('named.conf', 'root_key_updated', True) - return True - -def certificate_renewal_update(ca): - """ - Update certmonger certificate renewal configuration. - """ - dogtag_constants = dogtag.configured_constants() - - # bump version when requests is changed - version = 3 - requests = ( - ( - dogtag_constants.ALIAS_DIR, - 'auditSigningCert cert-pki-ca', - 'dogtag-ipa-ca-renew-agent', - 'stop_pkicad', - 'renew_ca_cert', - None, - ), - ( - dogtag_constants.ALIAS_DIR, - 'ocspSigningCert cert-pki-ca', - 'dogtag-ipa-ca-renew-agent', - 'stop_pkicad', - 'renew_ca_cert', - None, - ), - ( - dogtag_constants.ALIAS_DIR, - 'subsystemCert cert-pki-ca', - 'dogtag-ipa-ca-renew-agent', - 'stop_pkicad', - 'renew_ca_cert', - None, - ), - ( - dogtag_constants.ALIAS_DIR, - 'caSigningCert cert-pki-ca', - 'dogtag-ipa-ca-renew-agent', - 'stop_pkicad', - 'renew_ca_cert', - 'ipaCACertRenewal', - ), - ( - paths.HTTPD_ALIAS_DIR, - 'ipaCert', - 'dogtag-ipa-ca-renew-agent', - None, - 'renew_ra_cert', - None, - ), - ( - dogtag_constants.ALIAS_DIR, - 'Server-Cert cert-pki-ca', - 'dogtag-ipa-renew-agent', - 'stop_pkicad', - 'renew_ca_cert', - None, - ), - ) - - root_logger.info("[Update certmonger certificate renewal configuration to " - "version %d]" % version) - if not ca.is_configured(): - root_logger.info('CA is not configured') - return False - - state = 'certificate_renewal_update_%d' % version - if sysupgrade.get_upgrade_state('dogtag', state): - return False - - # State not set, lets see if we are already configured - for request in requests: - nss_dir, nickname, ca_name, pre_command, post_command, profile = request - criteria = { - 'cert-database': nss_dir, - 'cert-nickname': nickname, - 'ca-name': ca_name, - 'template-profile': profile, - } - request_id = certmonger.get_request_id(criteria) - if request_id is None: - break - - val = certmonger.get_request_value(request_id, 'cert-presave-command') - if val is not None: - val = val.split(' ', 1)[0] - val = os.path.basename(val) - if pre_command != val: - break - - val = certmonger.get_request_value(request_id, 'cert-postsave-command') - if val is not None: - val = val.split(' ', 1)[0] - val = os.path.basename(val) - if post_command != val: - break - else: - sysupgrade.set_upgrade_state('dogtag', state, True) - root_logger.info("Certmonger certificate renewal configuration is " - "already at version %d" % version) - return False - - # Ok, now we need to stop tracking, then we can start tracking them - # again with new configuration: - ca.stop_tracking_certificates() - - if not sysupgrade.get_upgrade_state('dogtag', - 'certificate_renewal_update_1'): - filename = paths.CERTMONGER_CAS_CA_RENEWAL - if os.path.exists(filename): - with installutils.stopped_service('certmonger'): - root_logger.info("Removing %s" % filename) - installutils.remove_file(filename) - - ca.configure_certmonger_renewal() - ca.configure_renewal() - ca.configure_agent_renewal() - ca.track_servercert() - - sysupgrade.set_upgrade_state('dogtag', state, True) - root_logger.info("Certmonger certificate renewal configuration updated to " - "version %d" % version) - return True - -def copy_crl_file(old_path, new_path=None): - """ - Copy CRL to new location, update permissions and SELinux context - """ - if new_path is None: - filename = os.path.basename(old_path) - new_path = os.path.join(dogtag.configured_constants().CRL_PUBLISH_PATH, - filename) - root_logger.debug('copy_crl_file: %s -> %s', old_path, new_path) - - if os.path.islink(old_path): - # update symlink to the most most recent CRL file - filename = os.path.basename(os.readlink(old_path)) - realpath = os.path.join(dogtag.configured_constants().CRL_PUBLISH_PATH, - filename) - root_logger.debug('copy_crl_file: Create symlink %s -> %s', - new_path, realpath) - os.symlink(realpath, new_path) - else: - shutil.copy2(old_path, new_path) - pent = pwd.getpwnam(cainstance.PKI_USER) - os.chown(new_path, pent.pw_uid, pent.pw_gid) - - tasks.restore_context(new_path) - -def migrate_crl_publish_dir(ca): - """ - Move CRL publish dir from /var/lib/pki-ca/publish to IPA controlled tree: - /var/lib/ipa/pki-ca/publish - """ - root_logger.info('[Migrate CRL publish directory]') - if sysupgrade.get_upgrade_state('dogtag', 'moved_crl_publish_dir'): - root_logger.info('CRL tree already moved') - return False - - if not ca.is_configured(): - root_logger.info('CA is not configured') - return False - - caconfig = dogtag.configured_constants() - - try: - old_publish_dir = installutils.get_directive(caconfig.CS_CFG_PATH, - 'ca.publish.publisher.instance.FileBaseCRLPublisher.directory', - separator='=') - except OSError, e: - root_logger.error('Cannot read CA configuration file "%s": %s', - caconfig.CS_CFG_PATH, e) - return False - - # Prepare target publish dir (creation, permissions, SELinux context) - # Run this every update to ensure proper values - publishdir = ca.prepare_crl_publish_dir() - - if old_publish_dir == caconfig.CRL_PUBLISH_PATH: - # publish dir is already updated - root_logger.info('Publish directory already set to new location') - sysupgrade.set_upgrade_state('dogtag', 'moved_crl_publish_dir', True) - return False - - # Copy all CRLs to new directory - root_logger.info('Copy all CRLs to new publish directory') - try: - crl_files_unsorted = cainstance.get_crl_files(old_publish_dir) - except OSError, e: - root_logger.error('Cannot move CRL files to new directory: %s', e) - else: - # Move CRL files at the end of the list to make sure that the actual - # CRL files are copied first - crl_files = sorted(crl_files_unsorted, - key=lambda f: os.path.islink(f)) - for f in crl_files: - try: - copy_crl_file(f) - except Exception, e: - root_logger.error('Cannot move CRL file to new directory: %s', e) - - try: - installutils.set_directive(caconfig.CS_CFG_PATH, - 'ca.publish.publisher.instance.FileBaseCRLPublisher.directory', - publishdir, quotes=False, separator='=') - except OSError, e: - root_logger.error('Cannot update CA configuration file "%s": %s', - caconfig.CS_CFG_PATH, e) - return False - sysupgrade.set_upgrade_state('dogtag', 'moved_crl_publish_dir', True) - root_logger.info('CRL publish directory has been migrated, ' - 'request pki-ca restart') - return True - - -def ca_enable_pkix(ca): - root_logger.info('[Enable PKIX certificate path discovery and validation]') - if sysupgrade.get_upgrade_state('dogtag', 'pkix_enabled'): - root_logger.info('PKIX already enabled') - return False - - if not ca.is_configured(): - root_logger.info('CA is not configured') - return False - - ca.enable_pkix() - sysupgrade.set_upgrade_state('dogtag', 'pkix_enabled', True) - - return True - - -def add_ca_dns_records(): - root_logger.info('[Add missing CA DNS records]') - - if sysupgrade.get_upgrade_state('dns', 'ipa_ca_records'): - root_logger.info('IPA CA DNS records already processed') - return - - if not api.Backend.ldap2.isconnected(): - try: - api.Backend.ldap2.connect(autobind=True) - except ipalib.errors.PublicError, e: - root_logger.error( - "Cannot connect to LDAP to add DNS records: %s", e) - return - - ret = api.Command['dns_is_enabled']() - if not ret['result']: - root_logger.info('DNS is not configured') - sysupgrade.set_upgrade_state('dns', 'ipa_ca_records', True) - return - - bind = bindinstance.BindInstance() - - bind.convert_ipa_ca_cnames(api.env.domain) - - # DNS is enabled, so let bindinstance find out if CA is enabled - # and let it add the record in that case - bind.add_ipa_ca_dns_records(api.env.host, api.env.domain, - ca_configured=None) - - sysupgrade.set_upgrade_state('dns', 'ipa_ca_records', True) - - -def find_subject_base(): - """ - Try to find the current value of certificate subject base. - See the docstring in dsinstance.DsInstance for details. - """ - subject_base = dsinstance.DsInstance().find_subject_base() - - if subject_base: - sysupgrade.set_upgrade_state( - 'certmap.conf', - 'subject_base', - subject_base - ) - return subject_base - - root_logger.error('Unable to determine certificate subject base. ' - 'certmap.conf will not be updated.') - - -def uninstall_selfsign(ds, http): - root_logger.info('[Removing self-signed CA]') - """Replace self-signed CA by a CA-less install""" - if api.env.ra_plugin != 'selfsign': - root_logger.debug('Self-signed CA is not installed') - return - - root_logger.warning( - 'Removing self-signed CA. Certificates will need to managed manually.') - p = ConfigParser.SafeConfigParser() - p.read(paths.IPA_DEFAULT_CONF) - p.set('global', 'enable_ra', 'False') - p.set('global', 'ra_plugin', 'none') - with open(paths.IPA_DEFAULT_CONF, 'w') as f: - p.write(f) - - ds.stop_tracking_certificates() - http.stop_tracking_certificates() - - -def mask_named_regular(): - """Disable named, we need to run only named-pkcs11, running both named and - named-pkcs can cause unexpected errors""" - if sysupgrade.get_upgrade_state('dns', 'regular_named_masked'): - return False - - sysupgrade.set_upgrade_state('dns', 'regular_named_masked', True) - - if bindinstance.named_conf_exists(): - root_logger.info('[Masking named]') - named = services.service('named-regular') - try: - named.stop() - except Exception as e: - root_logger.warning('Unable to stop named service (%s)', e) - - try: - named.mask() - except Exception as e: - root_logger.warning('Unable to mask named service (%s)', e) - - return True - - return False - - -def fix_dyndb_ldap_workdir_permissions(): - """Fix dyndb-ldap working dir permissions. DNSSEC daemons requires it""" - if sysupgrade.get_upgrade_state('dns', 'dyndb_ipa_workdir_perm'): - return - - if bindinstance.named_conf_exists(): - root_logger.info('[Fix bind-dyndb-ldap IPA working directory]') - dnskeysync = dnskeysyncinstance.DNSKeySyncInstance() - dnskeysync.set_dyndb_ldap_workdir_permissions() - - sysupgrade.set_upgrade_state('dns', 'dyndb_ipa_workdir_perm', True) - - -def fix_schema_file_syntax(): - """Fix syntax errors in schema files - - https://fedorahosted.org/freeipa/ticket/3578 - """ - root_logger.info('[Fix DS schema file syntax]') - - # This is not handled by normal schema updates, because pre-1.3.2 DS will - # ignore (auto-fix) these syntax errors, and 1.3.2 and above will choke on - # them before checking dynamic schema updates. - - if sysupgrade.get_upgrade_state('ds', 'fix_schema_syntax'): - root_logger.info('Syntax already fixed') - return - - serverid = installutils.realm_to_serverid(api.env.realm) - ds_dir = dsinstance.config_dirname(serverid) - - # 1. 60ipadns.ldif: Add parenthesis to idnsRecord - - filename = os.path.join(ds_dir, 'schema', '60ipadns.ldif') - result_lines = [] - with open(filename) as file: - for line in file: - line = line.strip('\n') - if (line.startswith('objectClasses:') and - "NAME 'idnsRecord'" in line and - line.count('(') == 2 and - line.count(')') == 1): - root_logger.debug('Add closing parenthesis in idnsRecord') - line += ' )' - result_lines.append(line) - - with open(filename, 'w') as file: - file.write('\n'.join(result_lines)) - - # 2. 65ipasudo.ldif: Remove extra dollar from ipaSudoRule - - filename = os.path.join(ds_dir, 'schema', '65ipasudo.ldif') - result_lines = [] - with open(filename) as file: - for line in file: - line = line.strip('\n') - if (line.startswith('objectClasses:') and - "NAME 'ipaSudoRule'" in line): - root_logger.debug('Remove extra dollar sign in ipaSudoRule') - line = line.replace('$$', '$') - result_lines.append(line) - - with open(filename, 'w') as file: - file.write('\n'.join(result_lines)) - - # Done - - sysupgrade.set_upgrade_state('ds', 'fix_schema_syntax', True) - - -def set_sssd_domain_option(option, value): - sssdconfig = SSSDConfig.SSSDConfig() - sssdconfig.import_config() - domain = sssdconfig.get_domain(str(api.env.domain)) - domain.set_option(option, value) - sssdconfig.save_domain(domain) - sssdconfig.write(paths.SSSD_CONF) - - -def remove_ds_ra_cert(subject_base): - root_logger.info('[Removing RA cert from DS NSS database]') - - if sysupgrade.get_upgrade_state('ds', 'remove_ra_cert'): - root_logger.info('RA cert already removed') - return - - dbdir = dsinstance.config_dirname( - installutils.realm_to_serverid(api.env.realm)) - dsdb = certs.CertDB(api.env.realm, nssdir=dbdir, subject_base=subject_base) - - nickname = 'CN=IPA RA,%s' % subject_base - cert = dsdb.get_cert_from_db(nickname) - if cert: - dsdb.delete_cert(nickname) - - sysupgrade.set_upgrade_state('ds', 'remove_ra_cert', True) - - -def fix_trust_flags(): - root_logger.info('[Fixing trust flags in %s]' % paths.HTTPD_ALIAS_DIR) - - if sysupgrade.get_upgrade_state('http', 'fix_trust_flags'): - root_logger.info("Trust flags already processed") - return - - if not api.Backend.ldap2.isconnected(): - try: - api.Backend.ldap2.connect(autobind=True) - except ipalib.errors.PublicError, e: - root_logger.error("Cannot connect to LDAP: %s", e) - return - - if not api.Command.ca_is_enabled()['result']: - root_logger.info("CA is not enabled") - return - - db = certs.CertDB(api.env.realm) - nickname = certdb.get_ca_nickname(api.env.realm) - cert = db.get_cert_from_db(nickname) - if cert: - db.trust_root_cert(nickname, 'CT,C,C') - - sysupgrade.set_upgrade_state('http', 'fix_trust_flags', True) - - -def update_mod_nss_protocol(http): - root_logger.info('[Updating mod_nss protocol versions]') - - if sysupgrade.get_upgrade_state('nss.conf', 'protocol_updated_tls12'): - root_logger.info("Protocol versions already updated") - return - - http.set_mod_nss_protocol() - - sysupgrade.set_upgrade_state('nss.conf', 'protocol_updated_tls12', True) - - -def main(): - """ - Get some basics about the system. If getting those basics fail then - this is likely because the machine isn't currently an IPA server so - exit gracefully. - """ - - if not os.geteuid()==0: - sys.exit("\nYou must be root to run this script.\n") - - if not installutils.is_ipa_configured(): - sys.exit(0) - - safe_options, options = parse_options() - - verbose = not options.quiet - if options.debug: - console_format = '%(levelname)s: %(message)s' - else: - console_format = '%(message)s' - - standard_logging_setup(paths.IPAUPGRADE_LOG, debug=options.debug, - verbose=verbose, console_format=console_format, filemode='a') - root_logger.debug('%s was invoked with options: %s' % (sys.argv[0], safe_options)) - root_logger.debug('IPA version %s' % version.VENDOR_VERSION) - - fstore = sysrestore.FileStore(paths.SYSRESTORE) - - api.bootstrap(context='restart', in_server=True) - api.finalize() - - fqdn = find_hostname() - if fqdn is None: - # ipa-rewrite.conf doesn't exist, nothing to do - sys.exit(0) - - # Ok, we are an IPA server, do the additional tests - - check_certs() - - auto_redirect = find_autoredirect(fqdn) - configured_constants = dogtag.configured_constants() - sub_dict = dict( - REALM=api.env.realm, - FQDN=fqdn, - AUTOREDIR='' if auto_redirect else '#', - CRL_PUBLISH_PATH=configured_constants.CRL_PUBLISH_PATH, - DOGTAG_PORT=configured_constants.AJP_PORT, - CLONE='#' - ) - - subject_base = find_subject_base() - if subject_base: - sub_dict['SUBJECT_BASE'] = subject_base - - ca = cainstance.CAInstance(api.env.realm, certs.NSS_DIR) - ca.backup_config() - - with installutils.stopped_service(configured_constants.SERVICE_NAME, - configured_constants.PKI_INSTANCE_NAME): - # migrate CRL publish dir before the location in ipa.conf is updated - ca_restart = migrate_crl_publish_dir(ca) - - if ca.is_configured(): - crl = installutils.get_directive(configured_constants.CS_CFG_PATH, - 'ca.crl.MasterCRL.enableCRLUpdates', '=') - sub_dict['CLONE']='#' if crl.lower() == 'true' else '' - - ds_serverid = installutils.realm_to_serverid(api.env.realm) - ds_dirname = dsinstance.config_dirname(ds_serverid) - - upgrade(sub_dict, paths.HTTPD_IPA_CONF, ipautil.SHARE_DIR + "ipa.conf") - upgrade(sub_dict, paths.HTTPD_IPA_REWRITE_CONF, ipautil.SHARE_DIR + "ipa-rewrite.conf") - if ca.is_configured(): - upgrade(sub_dict, paths.HTTPD_IPA_PKI_PROXY_CONF, ipautil.SHARE_DIR + "ipa-pki-proxy.conf", add=True) - else: - if ipautil.file_exists(paths.HTTPD_IPA_PKI_PROXY_CONF): - os.remove(paths.HTTPD_IPA_PKI_PROXY_CONF) - if subject_base: - upgrade( - sub_dict, - os.path.join(ds_dirname, "certmap.conf"), - os.path.join(ipautil.SHARE_DIR, "certmap.conf.template") - ) - upgrade_pki(ca, fstore) - - ca.configure_certmonger_renewal_guard() - - update_dbmodules(api.env.realm) - uninstall_ipa_kpasswd() - - removed_sysconfig_file = paths.SYSCONFIG_HTTPD - if fstore.has_file(removed_sysconfig_file): - root_logger.info('Restoring %s as it is no longer required', - removed_sysconfig_file) - fstore.restore_file(removed_sysconfig_file) - - http = httpinstance.HTTPInstance(fstore) - http.configure_selinux_for_httpd() - http.change_mod_nss_port_from_http() - http.configure_certmonger_renewal_guard() - - http.stop() - update_mod_nss_protocol(http) - fix_trust_flags() - http.start() - - ds = dsinstance.DsInstance() - ds.configure_dirsrv_ccache() - - ds.stop(ds_serverid) - fix_schema_file_syntax() - remove_ds_ra_cert(subject_base) - ds.start(ds_serverid) - - uninstall_selfsign(ds, http) - - simple_service_list = ( - (memcacheinstance.MemcacheInstance(), 'MEMCACHE'), - (otpdinstance.OtpdInstance(), 'OTPD'), - ) - - for service, ldap_name in simple_service_list: - service.ldapi = True - try: - if not service.is_configured(): - # 389-ds needs to be running to create the memcache instance - # because we record the new service in cn=masters. - ds.start() - service.create_instance(ldap_name, fqdn, None, - ipautil.realm_to_suffix(api.env.realm), - realm=api.env.realm) - except ipalib.errors.DuplicateEntry: - pass - - # install DNSKeySync service only if DNS is configured on server - if bindinstance.named_conf_exists(): - dnskeysyncd = dnskeysyncinstance.DNSKeySyncInstance(fstore, ldapi=True) - if not dnskeysyncd.is_configured(): - ds.start() - dnskeysyncd.create_instance(fqdn, api.env.realm) - dnskeysyncd.start_dnskeysyncd() - - cleanup_kdc(fstore) - cleanup_adtrust(fstore) - setup_firefox_extension(fstore) - add_ca_dns_records() - - # Any of the following functions returns True iff the named.conf file - # has been altered - named_conf_changes = ( - named_remove_deprecated_options(), - named_set_minimum_connections(), - named_enable_serial_autoincrement(), - named_update_gssapi_configuration(), - named_update_pid_file(), - named_enable_dnssec(), - named_validate_dnssec(), - named_bindkey_file_option(), - named_managed_keys_dir_option(), - named_root_key_include(), - mask_named_regular(), - fix_dyndb_ldap_workdir_permissions(), - ) - - if any(named_conf_changes): - # configuration has changed, restart the name server - root_logger.info('Changes to named.conf have been made, restart named') - bind = bindinstance.BindInstance(fstore) - try: - bind.restart() - except ipautil.CalledProcessError, e: - root_logger.error("Failed to restart %s: %s", bind.service_name, e) - - ca_restart = any([ - ca_restart, - upgrade_ipa_profile(ca, api.env.domain, fqdn), - certificate_renewal_update(ca), - ca_enable_pkix(ca), - ]) - - if ca_restart: - root_logger.info('pki-ca configuration changed, restart pki-ca') - try: - ca.restart(dogtag.configured_constants().PKI_INSTANCE_NAME) - except ipautil.CalledProcessError, e: - root_logger.error("Failed to restart %s: %s", ca.service_name, e) - set_sssd_domain_option('ipa_server_mode', 'True') if __name__ == '__main__': - installutils.run_script(main, operation_name='ipa-upgradeconfig') + sys.exit("Please run the 'ipa-server-upgrade' command to upgrade the " + "IPA server.") |