URL: https://github.com/freeipa/freeipa/pull/5376 Author: abbra Title: #5376: Fix uninstall without dns Action: opened
PR body: """ Service constructors are called even when the service itself is not configured. A common pattern in FreeIPA code is to instantiate a service and check whether it is configured, then perform uninstall of the service configuration. This fails if the service constructor does depend on the artifacts only present if other (relevant to the service) packages were installed. A common pattern is: ``` svc = SVCClass(..) if svc.is_configured(): svc.uninstall() ``` Most of DNS-related service classes do resolution of UID/GIDs for ODS and NAMED in their constructors which breaks uninstallation of a DNS-less FreeIPA deployment because neither 'bind' nor 'opendnssec' packages are not installed and user and group they provide are not available in the system. Fixes: https://pagure.io/freeipa/issue/8630 """ To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/5376/head:pr5376 git checkout pr5376
From 3ca0faa6a503da7216e6a66f3b63b359980a47cb Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy <aboko...@redhat.com> Date: Tue, 22 Dec 2020 09:11:51 +0200 Subject: [PATCH 1/3] opendnssecinstance: use late binding for UID/GID resolution Move actual resolution of UID/GID values for 'ods' and 'named' entities to the code that needs them. This prevents failures when uninstalling IPA server set up without DNS feature. In particular, 'named' group is created when 'bind' package is installed and if 'bind' package is not installed, uninstall fails in OpenDNSSEC instance constructor. We use common pattern for all services during uninstall: svc = SVCClass(..) if svc.is_configured() svc.uninstall() This requires that the class constructor should not rely on artifacts that only exist when the service is configured. Fixes: https://pagure.io/freeipa/issue/8630 Signed-off-by: Alexander Bokovoy <aboko...@redhat.com> --- ipaserver/install/opendnssecinstance.py | 29 ++++++++++++++----------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py index 415e7710ed1..ada7da573e2 100644 --- a/ipaserver/install/opendnssecinstance.py +++ b/ipaserver/install/opendnssecinstance.py @@ -67,9 +67,9 @@ def __init__(self, fstore=None): self, "ods-enforcerd", service_desc="OpenDNSSEC enforcer daemon", ) - self.named_gid = constants.NAMED_GROUP.gid - self.ods_uid = constants.ODS_USER.uid - self.ods_gid = constants.ODS_GROUP.gid + self.named_gid = constants.NAMED_GROUP + self.ods_uid = constants.ODS_USER + self.ods_gid = constants.ODS_GROUP self.conf_file_dict = { 'SOFTHSM_LIB': paths.LIBSOFTHSM2_SO, 'TOKEN_LABEL': SOFTHSM_DNSSEC_TOKEN_LABEL, @@ -194,8 +194,8 @@ def __setup_conf_files(self): quotes=False, separator='=') def __setup_ownership_file_modes(self): - assert self.ods_uid is not None - assert self.ods_gid is not None + assert self.ods_uid.uid is not None + assert self.ods_gid.gid is not None # workarounds for packaging bugs in opendnssec-1.4.5-2.fc20.x86_64 # https://bugzilla.redhat.com/show_bug.cgi?id=1098188 @@ -204,24 +204,24 @@ def __setup_ownership_file_modes(self): dir_path = os.path.join(root, directory) os.chmod(dir_path, 0o770) # chown to root:ods - os.chown(dir_path, 0, self.ods_gid) + os.chown(dir_path, 0, self.ods_gid.gid) for filename in files: file_path = os.path.join(root, filename) os.chmod(file_path, 0o660) # chown to root:ods - os.chown(file_path, 0, self.ods_gid) + os.chown(file_path, 0, self.ods_gid.gid) for (root, dirs, files) in os.walk(paths.VAR_OPENDNSSEC_DIR): for directory in dirs: dir_path = os.path.join(root, directory) os.chmod(dir_path, 0o770) # chown to ods:ods - os.chown(dir_path, self.ods_uid, self.ods_gid) + os.chown(dir_path, self.ods_uid.uid, self.ods_gid.gid) for filename in files: file_path = os.path.join(root, filename) os.chmod(file_path, 0o660) # chown to ods:ods - os.chown(file_path, self.ods_uid, self.ods_gid) + os.chown(file_path, self.ods_uid.uid, self.ods_gid.gid) def __generate_master_key(self): @@ -242,11 +242,13 @@ def __generate_master_key(self): for directory in dirs: dir_path = os.path.join(root, directory) os.chmod(dir_path, 0o770 | stat.S_ISGID) - os.chown(dir_path, self.ods_uid, self.named_gid) # chown to ods:named + # chown to ods:named + os.chown(dir_path, self.ods_uid.uid, self.named_gid.gid) for filename in files: file_path = os.path.join(root, filename) os.chmod(file_path, 0o660 | stat.S_ISGID) - os.chown(file_path, self.ods_uid, self.named_gid) # chown to ods:named + # chown to ods:named + os.chown(file_path, self.ods_uid.uid, self.named_gid.gid) finally: p11.finalize() @@ -266,7 +268,8 @@ def __setup_dnssec(self): # copy user specified kasp.db to proper location and set proper # privileges shutil.copy(self.kasp_db_file, paths.OPENDNSSEC_KASP_DB) - os.chown(paths.OPENDNSSEC_KASP_DB, self.ods_uid, self.ods_gid) + os.chown(paths.OPENDNSSEC_KASP_DB, + self.ods_uid.uid, self.ods_gid.gid) os.chmod(paths.OPENDNSSEC_KASP_DB, 0o660) else: @@ -290,7 +293,7 @@ def __start(self): ) with open(paths.OPENDNSSEC_ZONELIST_FILE, 'w') as f: f.write(result.output) - os.fchown(f.fileno(), self.ods_uid, self.ods_gid) + os.fchown(f.fileno(), self.ods_uid.uid, self.ods_gid.gid) os.fchmod(f.fileno(), 0o660) def uninstall(self): From d1a6abc47812230b4a267aec461db9b31864378f Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy <aboko...@redhat.com> Date: Tue, 22 Dec 2020 09:20:52 +0200 Subject: [PATCH 2/3] dnskeysyncinstance: use late binding for UID/GID resolution Move actual resolution of UID/GID values for 'ods' and 'named' entities to the code that needs them. This prevents failures when uninstalling IPA server set up without DNS feature. In particular, 'named' group is created when 'bind' package is installed and if 'bind' package is not installed, uninstall fails in OpenDNSSEC instance constructor. We use common pattern for all services during uninstall: svc = SVCClass(..) if svc.is_configured() svc.uninstall() This requires that the class constructor should not rely on artifacts that only exist when the service is configured. Fixes: https://pagure.io/freeipa/issue/8630 Signed-off-by: Alexander Bokovoy <aboko...@redhat.com> --- ipaserver/install/dnskeysyncinstance.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ipaserver/install/dnskeysyncinstance.py b/ipaserver/install/dnskeysyncinstance.py index 16870b73b5c..945ccf76935 100644 --- a/ipaserver/install/dnskeysyncinstance.py +++ b/ipaserver/install/dnskeysyncinstance.py @@ -55,10 +55,10 @@ def __init__(self, fstore=None, logger=logger): keytab=paths.IPA_DNSKEYSYNCD_KEYTAB ) self.extra_config = [u'dnssecVersion 1', ] # DNSSEC enabled - self.named_uid = constants.NAMED_USER.uid - self.named_gid = constants.NAMED_GROUP.gid - self.ods_uid = constants.ODS_USER.uid - self.ods_gid = constants.ODS_GROUP.gid + self.named_uid = constants.NAMED_USER + self.named_gid = constants.NAMED_GROUP + self.ods_uid = constants.ODS_USER + self.ods_gid = constants.ODS_GROUP suffix = ipautil.dn_attribute_property('_suffix') @@ -78,7 +78,7 @@ def set_dyndb_ldap_workdir_permissions(self): else: os.chmod(directory, 0o770) # dnssec daemons require to have access into the directory - os.chown(directory, self.named_uid, self.named_gid) + os.chown(directory, self.named_uid.uid, self.named_gid.gid) def remove_replica_public_keys(self, replica_fqdn): ldap = api.Backend.ldap2 @@ -180,7 +180,7 @@ def setup_named_openssl_conf(self): ) with open(paths.DNSSEC_OPENSSL_CONF, 'w') as f: os.fchmod(f.fileno(), 0o640) - os.fchown(f.fileno(), 0, self.named_gid) + os.fchown(f.fileno(), 0, self.named_gid.gid) f.write(named_openssl_txt) def setup_named_sysconfig(self): @@ -235,7 +235,7 @@ def __setup_softhsm(self): os.mkdir(paths.IPA_DNSSEC_DIR) os.chmod(paths.IPA_DNSSEC_DIR, 0o770) # chown ods:named - os.chown(paths.IPA_DNSSEC_DIR, self.ods_uid, self.named_gid) + os.chown(paths.IPA_DNSSEC_DIR, self.ods_uid.uid, self.named_gid.gid) # setup softhsm2 config file softhsm_conf_txt = ("# SoftHSM v2 configuration file \n" @@ -272,7 +272,7 @@ def __setup_softhsm(self): os.mkdir(paths.DNSSEC_TOKENS_DIR) os.chmod(paths.DNSSEC_TOKENS_DIR, 0o770 | stat.S_ISGID) # chown to ods:named - os.chown(paths.DNSSEC_TOKENS_DIR, self.ods_uid, self.named_gid) + os.chown(paths.DNSSEC_TOKENS_DIR, self.ods_uid.uid, self.named_gid.gid) # generate PINs for softhsm pin_length = 30 # Bind allows max 32 bytes including ending '\0' @@ -284,7 +284,7 @@ def __setup_softhsm(self): logger.debug("Saving user PIN to %s", paths.DNSSEC_SOFTHSM_PIN) with open(paths.DNSSEC_SOFTHSM_PIN, 'w') as f: # chown to ods:named - os.fchown(f.fileno(), self.ods_uid, self.named_gid) + os.fchown(f.fileno(), self.ods_uid.uid, self.named_gid.gid) os.fchmod(f.fileno(), 0o660) f.write(pin) @@ -419,12 +419,12 @@ def __setup_replica_keys(self): dir_path = os.path.join(root, directory) os.chmod(dir_path, 0o770 | stat.S_ISGID) # chown to ods:named - os.chown(dir_path, self.ods_uid, self.named_gid) + os.chown(dir_path, self.ods_uid.uid, self.named_gid.gid) for filename in files: file_path = os.path.join(root, filename) os.chmod(file_path, 0o660 | stat.S_ISGID) # chown to ods:named - os.chown(file_path, self.ods_uid, self.named_gid) + os.chown(file_path, self.ods_uid.uid, self.named_gid.gid) def __enable(self): try: @@ -449,7 +449,7 @@ def __setup_principal(self): dnssynckey_principal_dn = p # Make sure access is strictly reserved to the named user - os.chown(self.keytab, 0, self.ods_gid) + os.chown(self.keytab, 0, self.ods_gid.gid) os.chmod(self.keytab, 0o440) dns_group = DN(('cn', 'DNS Servers'), ('cn', 'privileges'), From 950fe59f849618eb9e101c613502cca05a7f5d49 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy <aboko...@redhat.com> Date: Tue, 22 Dec 2020 09:25:01 +0200 Subject: [PATCH 3/3] odsexporterinstance: use late binding for UID/GID resolution Move actual resolution of UID/GID values for 'ods' entities to the code that needs them. This prevents failures when uninstalling IPA server set up without DNS feature. In particular, 'ods' user and group are created when 'opendnssec' package is installed and if 'opendnssec' package is not installed, uninstall fails in OpenDNSSEC Exporter instance constructor. We use common pattern of checking the service during uninstall: svc = SVCClass() if svc.is_configured(): svc.uninstall() Thus, service class constructor must not do UID/GID resolution Fixes: https://pagure.io/freeipa/issue/8630 Signed-off-by: Alexander Bokovoy <aboko...@redhat.com> --- ipaserver/install/odsexporterinstance.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ipaserver/install/odsexporterinstance.py b/ipaserver/install/odsexporterinstance.py index d9fa46d0a36..e0359130b90 100644 --- a/ipaserver/install/odsexporterinstance.py +++ b/ipaserver/install/odsexporterinstance.py @@ -31,8 +31,8 @@ def __init__(self, fstore=None): keytab=paths.IPA_ODS_EXPORTER_KEYTAB, service_prefix=u'ipa-ods-exporter' ) - self.ods_uid = constants.ODS_USER.uid - self.ods_gid = constants.ODS_GROUP.gid + self.ods_uid = constants.ODS_USER + self.ods_gid = constants.ODS_GROUP self.enable_if_exists = False suffix = ipautil.dn_attribute_property('_suffix') @@ -71,7 +71,7 @@ def __setup_key_exporter(self): quotes=False, separator='=') def __setup_principal(self): - assert self.ods_uid is not None + assert self.ods_uid.uid is not None for f in [paths.IPA_ODS_EXPORTER_CCACHE, self.keytab]: try: @@ -95,7 +95,7 @@ def __setup_principal(self): # Make sure access is strictly reserved to the ods user os.chmod(self.keytab, 0o440) - os.chown(self.keytab, 0, self.ods_gid) + os.chown(self.keytab, 0, self.ods_gid.gid) dns_group = DN(('cn', 'DNS Servers'), ('cn', 'privileges'), ('cn', 'pbac'), self.suffix)
_______________________________________________ FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedorahosted.org/archives/list/freeipa-devel@lists.fedorahosted.org