diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py index 702da6b7e..8cf6fded1 100644 --- a/ipaplatform/base/tasks.py +++ b/ipaplatform/base/tasks.py @@ -227,7 +227,8 @@ class BaseTaskNamespace(object): else: log.debug('user %s exists', name) - def parse_ipa_version(self, version): + @staticmethod + def parse_ipa_version(version): """ :param version: textual version :return: object implementing proper __cmp__ method for version compare diff --git a/ipaplatform/debian/__init__.py b/ipaplatform/debian/__init__.py new file mode 100644 index 000000000..63052707b --- /dev/null +++ b/ipaplatform/debian/__init__.py @@ -0,0 +1,7 @@ +# +# Copyright (C) 2017 FreeIPA Contributors see COPYING for license +# + +""" +This module contains Debian specific platform files. +""" diff --git a/ipaplatform/debian/constants.py b/ipaplatform/debian/constants.py new file mode 100644 index 000000000..1edcb5adc --- /dev/null +++ b/ipaplatform/debian/constants.py @@ -0,0 +1,25 @@ +# +# Copyright (C) 2017 FreeIPA Contributors see COPYING for license +# + +''' +This Debian family platform module exports platform dependant constants. +''' + +# Fallback to default path definitions +from ipaplatform.base.constants import BaseConstantsNamespace + + +class DebianConstantsNamespace(BaseConstantsNamespace): + HTTPD_USER = "www-data" + NAMED_USER = "bind" + NAMED_GROUP = "bind" + # ntpd init variable used for daemon options + NTPD_OPTS_VAR = "NTPD_OPTS" + # quote used for daemon options + NTPD_OPTS_QUOTE = "\'" + ODS_USER = "opendnssec" + ODS_GROUP = "opendnssec" + SECURE_NFS_VAR = "NEED_GSSD" + +constants = DebianConstantsNamespace() diff --git a/ipaplatform/debian/paths.py b/ipaplatform/debian/paths.py new file mode 100644 index 000000000..5cbe9b876 --- /dev/null +++ b/ipaplatform/debian/paths.py @@ -0,0 +1,96 @@ +# +# Copyright (C) 2017 FreeIPA Contributors see COPYING for license +# + +""" +This Debian base platform module exports default filesystem paths as common +in Debian-based systems. +""" + +# Fallback to default path definitions +from ipaplatform.base.paths import BasePathNamespace +import sysconfig + +MULTIARCH = sysconfig.get_config_var('MULTIARCH') + +class DebianPathNamespace(BasePathNamespace): + BIN_HOSTNAMECTL = "/usr/bin/hostnamectl" + AUTOFS_LDAP_AUTH_CONF = "/etc/autofs_ldap_auth.conf" + ETC_HTTPD_DIR = "/etc/apache2" + HTTPD_ALIAS_DIR = "/etc/apache2/nssdb" + ALIAS_CACERT_ASC = "/etc/apache2/nssdb/cacert.asc" + ALIAS_PWDFILE_TXT = "/etc/apache2/nssdb/pwdfile.txt" + HTTPD_CONF_D_DIR = "/etc/apache2/conf-enabled/" + HTTPD_IPA_KDCPROXY_CONF_SYMLINK = "/etc/apache2/conf-enabled/ipa-kdc-proxy.conf" + HTTPD_IPA_PKI_PROXY_CONF = "/etc/apache2/conf-enabled/ipa-pki-proxy.conf" + HTTPD_IPA_REWRITE_CONF = "/etc/apache2/conf-available/ipa-rewrite.conf" + HTTPD_IPA_CONF = "/etc/apache2/conf-enabled/ipa.conf" + HTTPD_NSS_CONF = "/etc/apache2/mods-available/nss.conf" + IPA_KEYTAB = "/etc/apache2/ipa.keytab" + HTTPD_PASSWORD_CONF = "/etc/apache2/password.conf" + NAMED_CONF = "/etc/bind/named.conf" + NAMED_VAR_DIR = "/var/cache/bind" + NAMED_KEYTAB = "/etc/bind/named.keytab" + NAMED_RFC1912_ZONES = "/etc/bind/named.conf.default-zones" + NAMED_ROOT_KEY = "/etc/bind/bind.keys" + NAMED_BINDKEYS_FILE = "/etc/bind/bind.keys" + NAMED_MANAGED_KEYS_DIR = "/var/cache/bind/dynamic" + OPENLDAP_LDAP_CONF = "/etc/ldap/ldap.conf" + ETC_DEBIAN_VERSION = "/etc/debian_version" + IPA_P11_KIT = "/usr/local/share/ca-certificates/ipa-ca.crt" + ETC_SYSCONFIG_DIR = "/etc/default" + SYSCONFIG_AUTOFS = "/etc/default/autofs" + SYSCONFIG_DIRSRV = "/etc/default/dirsrv" + SYSCONFIG_DIRSRV_INSTANCE = "/etc/default/dirsrv-%s" + SYSCONFIG_DIRSRV_SYSTEMD = "/etc/default/dirsrv.systemd" + SYSCONFIG_IPA_DNSKEYSYNCD = "/etc/default/ipa-dnskeysyncd" + SYSCONFIG_IPA_ODS_EXPORTER = "/etc/default/ipa-ods-exporter" + SYSCONFIG_KRB5KDC_DIR = "/etc/default/krb5-kdc" + SYSCONFIG_NAMED = "/etc/default/bind9" + SYSCONFIG_NFS = "/etc/default/nfs-common" + SYSCONFIG_NTPD = "/etc/default/ntp" + SYSCONFIG_ODS = "/etc/default/opendnssec" + SYSCONFIG_PKI = "/etc/dogtag/" + SYSCONFIG_PKI_TOMCAT = "/etc/default/pki-tomcat" + SYSCONFIG_PKI_TOMCAT_PKI_TOMCAT_DIR = "/etc/dogtag/tomcat/pki-tomcat" + SYSTEMD_SYSTEM_HTTPD_D_DIR = "/etc/systemd/system/apache2.service.d/" + SYSTEMD_SYSTEM_HTTPD_IPA_CONF = "/etc/systemd/system/apache2.service.d/ipa.conf" + DNSSEC_TRUSTED_KEY = "/etc/bind/trusted-key.key" + KRA_AGENT_PEM = "/etc/apache2/nssdb/kra-agent.pem" + SBIN_SERVICE = "/usr/sbin/service" + CERTMONGER_COMMAND_TEMPLATE = "/usr/lib/ipa/certmonger/%s" + UPDATE_CA_TRUST = "/usr/sbin/update-ca-certificates" + BIND_LDAP_DNS_IPA_WORKDIR = "/var/cache/bind/dyndb-ldap/ipa/" + BIND_LDAP_DNS_ZONE_WORKDIR = "/var/cache/bind/dyndb-ldap/ipa/master/" + LIBSOFTHSM2_SO = "/usr/lib/softhsm/libsofthsm2.so" + PAM_KRB5_SO = "/usr/lib/{0}/security/pam_krb5.so".format(MULTIARCH) + LIB_SYSTEMD_SYSTEMD_DIR = "/lib/systemd/system/" + DOGTAG_IPA_CA_RENEW_AGENT_SUBMIT = "/usr/lib/certmonger/dogtag-ipa-ca-renew-agent-submit" + DOGTAG_IPA_RENEW_AGENT_SUBMIT = "/usr/lib/certmonger/dogtag-ipa-renew-agent-submit" + IPA_SERVER_GUARD = "/usr/lib/certmonger/ipa-server-guard" + GENERATE_RNDC_KEY = "/bin/true" + IPA_DNSKEYSYNCD_REPLICA = "/usr/lib/ipa/ipa-dnskeysync-replica" + IPA_DNSKEYSYNCD = "/usr/lib/ipa/ipa-dnskeysyncd" + IPA_ODS_EXPORTER = "/usr/lib/ipa/ipa-ods-exporter" + HTTPD = "/usr/sbin/apache2ctl" + REMOVE_DS_PL = "/usr/sbin/remove-ds" + SETUP_DS_PL = "/usr/sbin/setup-ds" + VAR_KERBEROS_KRB5KDC_DIR = "/var/lib/krb5kdc/" + VAR_KRB5KDC_K5_REALM = "/var/lib/krb5kdc/.k5." + CACERT_PEM = "/var/lib/krb5kdc/cacert.pem" + KRB5KDC_KADM5_ACL = "/etc/krb5kdc/kadm5.acl" + KRB5KDC_KADM5_KEYTAB = "/etc/krb5kdc/kadm5.keytab" + KRB5KDC_KDC_CONF = "/etc/krb5kdc/kdc.conf" + KDC_CERT = "/var/lib/krb5kdc/kdc.crt" + KDC_KEY = "/var/lib/krb5kdc/kdc.key" + VAR_LOG_HTTPD_DIR = "/var/log/apache2" + VAR_LOG_HTTPD_ERROR = "/var/log/apache2/error.log" + NAMED_RUN = "/var/cache/bind/named.run" + VAR_OPENDNSSEC_DIR = "/var/lib/opendnssec" + OPENDNSSEC_KASP_DB = "/var/lib/opendnssec/db/kasp.db" + IPA_ODS_EXPORTER_CCACHE = "/var/lib/opendnssec/tmp/ipa-ods-exporter.ccache" + KRB5CC_HTTPD = "/var/run/apache2/ipa/krbcache/krb5ccache" + IPA_CUSTODIA_SOCKET = "/run/apache2/ipa-custodia.sock" + IPA_CUSTODIA_AUDIT_LOG = '/var/log/ipa-custodia.audit.log' + +paths = DebianPathNamespace() diff --git a/ipaplatform/debian/services.py b/ipaplatform/debian/services.py new file mode 100644 index 000000000..82a74e2d6 --- /dev/null +++ b/ipaplatform/debian/services.py @@ -0,0 +1,184 @@ +# +# Copyright (C) 2017 FreeIPA Contributors see COPYING for license +# + +""" +Contains Debian-specific service class implementations. +""" + +from ipaplatform.base import services as base_services +from ipaplatform.redhat import services as redhat_services +from ipapython import ipautil +from ipaplatform.paths import paths + +# Mappings from service names as FreeIPA code references to these services +# to their actual systemd service names +debian_system_units = redhat_services.redhat_system_units.copy() + +# For beginning just remap names to add .service +# As more services will migrate to systemd, unit names will deviate and +# mapping will be kept in this dictionary +debian_system_units['httpd'] = 'apache2.service' +debian_system_units['kadmin'] = 'krb5-admin-server.service' +debian_system_units['krb5kdc'] = 'krb5-kdc.service' +debian_system_units['named-regular'] = 'bind9.service' +debian_system_units['named-pkcs11'] = 'bind9-pkcs11.service' +debian_system_units['named'] = debian_system_units['named-pkcs11'] +debian_system_units['pki-tomcatd'] = 'pki-tomcatd.service' +debian_system_units['pki_tomcatd'] = debian_system_units['pki-tomcatd'] +debian_system_units['ods-enforcerd'] = 'opendnssec-enforcer.service' +debian_system_units['ods_enforcerd'] = debian_system_units['ods-enforcerd'] +debian_system_units['ods-signerd'] = 'opendnssec-signer.service' +debian_system_units['ods_signerd'] = debian_system_units['ods-signerd'] +debian_system_units['rpcgssd'] = 'rpc-gssd.service' +debian_system_units['rpcidmapd'] = 'nfs-idmapd.service' +debian_system_units['smb'] = 'smbd.service' + +# Service classes that implement Debian family-specific behaviour + +class DebianService(redhat_services.RedHatService): + system_units = debian_system_units + + +class DebianSysvService(base_services.PlatformService): + def __wait_for_open_ports(self, instance_name=""): + """ + If this is a service we need to wait for do so. + """ + ports = None + if instance_name in base_services.wellknownports: + ports = base_services.wellknownports[instance_name] + else: + if self.service_name in base_services.wellknownports: + ports = base_services.wellknownports[self.service_name] + if ports: + ipautil.wait_for_open_ports('localhost', ports, self.api.env.startup_timeout) + + def stop(self, instance_name='', capture_output=True): + ipautil.run([paths.SBIN_SERVICE, self.service_name, "stop", + instance_name], capture_output=capture_output) + super(DebianSysvService, self).stop(instance_name) + + def start(self, instance_name='', capture_output=True, wait=True): + ipautil.run([paths.SBIN_SERVICE, self.service_name, "start", + instance_name], capture_output=capture_output) + if wait and self.is_running(instance_name): + self.__wait_for_open_ports(instance_name) + super(DebianSysvService, self).start(instance_name) + + def restart(self, instance_name='', capture_output=True, wait=True): + ipautil.run([paths.SBIN_SERVICE, self.service_name, "restart", + instance_name], capture_output=capture_output) + if wait and self.is_running(instance_name): + self.__wait_for_open_ports(instance_name) + + def is_running(self, instance_name=""): + ret = True + try: + result = ipautil.run([paths.SBIN_SERVICE, + self.service_name, "status", + instance_name], + capture_output=True) + sout = result.output + if sout.find("NOT running") >= 0: + ret = False + if sout.find("stop") >= 0: + ret = False + if sout.find("inactive") >= 0: + ret = False + except ipautil.CalledProcessError: + ret = False + return ret + + def is_installed(self): + installed = True + try: + ipautil.run([paths.SBIN_SERVICE, self.service_name, "status"]) + except ipautil.CalledProcessError as e: + if e.returncode == 1: + # service is not installed or there is other serious issue + installed = False + return installed + + @staticmethod + def is_enabled(instance_name=""): + # Services are always assumed to be enabled when installed + return True + + @staticmethod + def enable(): + return True + + @staticmethod + def disable(): + return True + + @staticmethod + def install(): + return True + + @staticmethod + def remove(): + return True + + @staticmethod + def tune_nofile_platform(): + return True + + +# For services which have no Debian counterpart +class DebianNoService(base_services.PlatformService): + @staticmethod + def start(): + return True + + @staticmethod + def stop(): + return True + + @staticmethod + def restart(): + return True + + @staticmethod + def disable(): + return True + + +# Function that constructs proper Debian-specific server classes for services +# of specified name + +def debian_service_class_factory(name, api=None): + if name == 'dirsrv': + return redhat_services.RedHatDirectoryService(name, api) + if name == 'domainname': + return DebianNoService(name, api) + if name == 'ipa': + return redhat_services.RedHatIPAService(name, api) + if name == 'messagebus': + return DebianNoService(name, api) + if name == 'ntpd': + return DebianSysvService("ntp", api) + return DebianService(name, api) + + +# Magicdict containing DebianService instances. + +class DebianServices(base_services.KnownServices): + def __init__(self): + import ipalib # FixMe: break import cycle + services = dict() + for s in base_services.wellknownservices: + services[s] = self.service_class_factory(s, ipalib.api) + # Call base class constructor. This will lock services to read-only + super(DebianServices, self).__init__(services) + + @staticmethod + def service_class_factory(name, api=None): + return debian_service_class_factory(name, api) + +# Objects below are expected to be exported by platform module + +timedate_services = base_services.timedate_services +service = debian_service_class_factory +knownservices = DebianServices() diff --git a/ipaplatform/debian/tasks.py b/ipaplatform/debian/tasks.py new file mode 100644 index 000000000..6c41a35e7 --- /dev/null +++ b/ipaplatform/debian/tasks.py @@ -0,0 +1,50 @@ +# +# Copyright (C) 2017 FreeIPA Contributors see COPYING for license +# + +""" +This module contains default Debian-specific implementations of system tasks. +""" + +from ipaplatform.base.tasks import BaseTaskNamespace +from ipaplatform.redhat.tasks import RedHatTaskNamespace + + +class DebianTaskNamespace(RedHatTaskNamespace): + @staticmethod + def restore_pre_ipa_client_configuration(fstore, statestore, + was_sssd_installed, + was_sssd_configured): + # Debian doesn't use authconfig, nothing to restore + return True + + @staticmethod + def set_nisdomain(nisdomain): + # Debian doesn't use authconfig, nothing to set + return True + + @staticmethod + def modify_nsswitch_pam_stack(sssd, mkhomedir, statestore): + # Debian doesn't use authconfig, this is handled by pam-auth-update + return True + + @staticmethod + def modify_pam_to_use_krb5(statestore): + # Debian doesn't use authconfig, this is handled by pam-auth-update + return True + + @staticmethod + def backup_auth_configuration(path): + # Debian doesn't use authconfig, nothing to backup + return True + + @staticmethod + def restore_auth_configuration(path): + # Debian doesn't use authconfig, nothing to restore + return True + + @staticmethod + def parse_ipa_version(version): + return BaseTaskNamespace.parse_ipa_version(version) + +tasks = DebianTaskNamespace() diff --git a/ipaplatform/setup.py b/ipaplatform/setup.py index 9c47da716..66378309c 100644 --- a/ipaplatform/setup.py +++ b/ipaplatform/setup.py @@ -35,6 +35,7 @@ if __name__ == '__main__': packages=[ "ipaplatform", "ipaplatform.base", + "ipaplatform.debian", "ipaplatform.fedora", "ipaplatform.redhat", "ipaplatform.rhel"