From 3687d4e28a45b1896165e2e1d029fc81bf5a2a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Fri, 23 Feb 2024 13:25:50 +0100 Subject: [PATCH 06/11] configure: drop authconfig compat tool authconfig-compat tool is now dropped and it can no longer be enabled via configure switch --- Makefile.am | 1 - configure.ac | 2 - po/POTFILES.in | 6 - src/compat/Makefile.am | 47 -- src/compat/authcompat.py.in.in | 665 ----------------------- src/compat/authcompat_ConfigSnippet.py | 92 ---- src/compat/authcompat_EnvironmentFile.py | 216 -------- src/compat/authcompat_Options.py | 326 ----------- src/compat/snippets/authconfig-krb.conf | 14 - src/compat/snippets/authconfig-sssd.conf | 18 - src/conf_macros.m4 | 9 - 11 files changed, 1396 deletions(-) delete mode 100644 src/compat/Makefile.am delete mode 100755 src/compat/authcompat.py.in.in delete mode 100644 src/compat/authcompat_ConfigSnippet.py delete mode 100644 src/compat/authcompat_EnvironmentFile.py delete mode 100644 src/compat/authcompat_Options.py delete mode 100644 src/compat/snippets/authconfig-krb.conf delete mode 100644 src/compat/snippets/authconfig-sssd.conf diff --git a/Makefile.am b/Makefile.am index 1c9b88d47f809cb218d19887734769f12b944bb4..befa38ba16f2ff6659fe452c4e4f8d9f646b3d84 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,6 @@ SUBDIRS= \ po \ profiles \ src/common \ - src/compat \ src/lib \ src/cli \ src/tests \ diff --git a/configure.ac b/configure.ac index 3a355bb78dd8040cd91f32e5602a55bf34a9563b..612763702cda22737ad841dd246dafbb607c0bed 100644 --- a/configure.ac +++ b/configure.ac @@ -51,8 +51,6 @@ AC_CONFIG_FILES([Makefile profiles/Makefile rpm/authselect.spec src/common/Makefile - src/compat/authcompat.py.in - src/compat/Makefile src/cli/Makefile src/lib/Makefile src/lib/authselect.pc diff --git a/po/POTFILES.in b/po/POTFILES.in index 2e7fbc89bbffe3a7584cf48bb99509d0912854e9..1380ba855ab4c9c2d35f956736cb195d4890042d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -26,9 +26,3 @@ src/common/format.c # Command line tool src/cli/cli_tool.c src/cli/main.c - -# Compat tool -src/compat/authcompat_ConfigSnippet.py -src/compat/authcompat_EnvironmentFile.py -src/compat/authcompat_Options.py -src/compat/authcompat.py.in.in diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am deleted file mode 100644 index 5928e53a22d432247a2ce1e120dcad699d3c961e..0000000000000000000000000000000000000000 --- a/src/compat/Makefile.am +++ /dev/null @@ -1,47 +0,0 @@ -if BUILD_COMPAT -expand_prefix = \ - ( \ - $(SED) -e 's,$${exec_prefix},$(exec_prefix),g' | \ - $(SED) -e 's,$${prefix},$(prefix),g' \ - ) - -generated_files = \ - authcompat.py \ - $(NULL) - -expand_files: - for FILE in $(generated_files) ; do \ - $(expand_prefix) < $$FILE.in > $$FILE ; \ - done - -.PHONY: expand_files -BUILT_SOURCES = expand_files - -CLEANFILES = \ - $(generated_files) \ - $(NULL) - -pkgpython_SCRIPTS = \ - authcompat.py \ - $(NULL) - -dist_pkgpython_DATA = \ - authcompat_ConfigSnippet.py \ - authcompat_EnvironmentFile.py \ - authcompat_Options.py \ - $(NULL) - -snippetsdir = $(pkgpythondir)/snippets -dist_snippets_DATA = \ - snippets/authconfig-krb.conf \ - snippets/authconfig-sssd.conf \ - $(NULL) - -# Create symbolic link that will replace authconfig -install-exec-hook: - $(MKDIR_P) $(DESTDIR)/$(sbindir) - $(LN_S) -f $(pkgpythondir)/authcompat.py $(DESTDIR)/$(sbindir)/authconfig - -uninstall-local: - $(RM) $(DESTDIR)/$(sbindir)/authconfig -endif diff --git a/src/compat/authcompat.py.in.in b/src/compat/authcompat.py.in.in deleted file mode 100755 index 6bea49829410e280ea06d19e265bad552ac93b02..0000000000000000000000000000000000000000 --- a/src/compat/authcompat.py.in.in +++ /dev/null @@ -1,665 +0,0 @@ -#!@PYTHON_BIN@ -# -*- coding: utf-8 -*- -# -# Authors: -# Pavel Březina -# -# Copyright (C) 2018 Red Hat -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -import sys -import locale -import gettext -import subprocess - - -from authcompat_Options import Options -from authcompat_EnvironmentFile import EnvironmentFile -from authcompat_ConfigSnippet import ConfigSnippet - -_ = gettext.gettext - - -def eprint(*args, **kwargs): - print(*args, file=sys.stderr, **kwargs) - - -class Command: - TEST = False - - def __init__(self, command, args, input=None, check=True): - self.args = [command] + args - self.input = input.encode() if input is not None else None - self.check = check - self.result = None - - def run(self): - print(_("Executing: %s") % ' '.join(self.args)) - - if self.TEST: - return - - self.result = subprocess.run(self.args, check=self.check, - input=self.input, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - - -class Service: - def __init__(self, name): - self.name = name + '.service' - - def runsystemd(self, command, required, enoent_code): - try: - command.run() - except subprocess.CalledProcessError as result: - if required and result.returncode == enoent_code: - eprint(_("Service %s was not found. Please install the service.") - % self.name) - elif result.returncode != enoent_code: - eprint(_("Command [%s] failed with %d, stderr:") - % (' '.join(result.cmd), result.returncode)) - eprint(result.stderr.decode()) - - def enable(self): - cmd = Command(Path.System("cmd-systemctl"), ["enable", self.name]) - self.runsystemd(cmd, True, 1) - - def disable(self): - cmd = Command(Path.System("cmd-systemctl"), ["disable", self.name]) - self.runsystemd(cmd, False, 1) - - def start(self, Restart=True): - if Restart: - self.stop() - cmd = Command(Path.System("cmd-systemctl"), ["start", self.name]) - self.runsystemd(cmd, True, 5) - - def stop(self): - cmd = Command(Path.System("cmd-systemctl"), ["stop", self.name]) - self.runsystemd(cmd, False, 5) - - -class Path: - LocalDir = os.path.dirname(os.path.realpath(__file__)) - Config = EnvironmentFile(LocalDir + "/authcompat_paths") - - Files = { - 'ldap.conf': '@sysconfdir@/openldap/ldap.conf', - 'krb5.conf': '@sysconfdir@/krb5.conf.d/authconfig-krb.conf', - 'sssd.conf': '@sysconfdir@/sssd/conf.d/authconfig-sssd.conf', - 'authconfig': '@sysconfdir@/sysconfig/authconfig', - 'network': '@sysconfdir@/sysconfig/network', - 'pwquality.conf': '@sysconfdir@/security/pwquality.conf.d/10-authconfig-pwquality.conf', - 'yp.conf': '@sysconfdir@/yp.conf', - 'cmd-systemctl': '@bindir@/systemctl', - 'cmd-authselect': '@bindir@/authselect', - 'cmd-realm': '@sbindir@/realm', - 'cmd-domainname': '@bindir@/domainname', - 'cmd-setsebool': '@sbindir@/setsebool' - } - - @staticmethod - def Local(relpath): - return "%s/%s" % (Path.LocalDir, relpath) - - @staticmethod - def System(name): - return Path.Files[name] - - -class Configuration: - class Base(object): - def __init__(self, options, ServiceName=None): - self.options = options - self.service = None - if ServiceName is not None: - self.service = Service(ServiceName) - - def isEnabled(self): - return True - - def isDisabled(self): - return not self.isEnabled() - - def enableService(self, nostart): - if self.service is None: - return - - self.service.enable() - - if not nostart: - self.service.start() - - def disableService(self, nostop): - if self.service is None: - return - - self.service.disable() - - if not nostop: - self.service.stop() - - def cleanup(self): - return - - def write(self): - return - - def get(self, name): - return self.options.get(name) - - def isset(self, name): - return self.options.isset(name) - - def getTrueOrNone(self, name): - return self.options.getTrueOrNone(name) - - def getBool(self, name): - return self.options.getBool(name) - - def getBoolAsValue(self, name, if_true, if_false, AllowNone=False): - if AllowNone and not self.isset(name): - return None - - value = self.getBool(name) - if value: - return if_true - - return if_false - - def removeFile(self, filename): - print(_("Removing file: %s") % filename) - if self.options.getBool("test-call"): - return - - try: - os.remove(filename) - except FileNotFoundError: - return - - class LDAP(Base): - def __init__(self, options): - super(Configuration.LDAP, self).__init__(options) - - def write(self): - config = EnvironmentFile(Path.System('ldap.conf'), " ", - delimiter_re=r"\s\t", quotes=False) - if self.isset("ldapserver"): - config.set("URI", self.get("ldapserver")) - - if self.isset("ldapbasedn"): - config.set("BASE", self.get("ldapbasedn")) - - config.write() - - class Kerberos(Base): - def __init__(self, options): - super(Configuration.Kerberos, self).__init__(options) - - def isEnabled(self): - if not self.isset("krb5realm") and not self.isset("krb5realmdns"): - return None - - return self.get("krb5realm") != "" or self.getBool("krb5realmdns") - - def cleanup(self): - # Do not remove the file if these options are not set - if not self.isset("krb5realm") and not self.isset("krb5realmdns"): - return - - self.removeFile(Path.System('krb5.conf')) - - def write(self): - if self.isDisabled(): - return - - path = Path.Local("snippets/authconfig-krb.conf") - config = ConfigSnippet(path, Path.System('krb5.conf')) - realm = self.get("krb5realm") - - keys = { - 'realm': self.get("krb5realm"), - 'kdc-srv': self.get("krb5kdcdns"), - 'realm-srv': self.get("krb5realmdns"), - 'kdc': self.get("krb5kdc") if realm else None, - 'adminserver': self.get("krb5adminserver") if realm else None, - 'domain': realm.lower() if realm else None - } - - config.write(keys) - - class Network(Base): - def __init__(self, options): - super(Configuration.Network, self).__init__(options) - - def write(self): - nisdomain = self.get("nisdomain") - config = EnvironmentFile(Path.System('network')) - - if nisdomain is None: - return - - config.set("NISDOMAIN", nisdomain) - config.write() - - class SSSD(Base): - def __init__(self, options): - super(Configuration.SSSD, self).__init__(options, ServiceName="sssd") - - def isEnabled(self): - if not self.isset("ldap") and not self.isset("sssd"): - return None - - return self.getBool("ldap") or self.getBool("sssd") - - def cleanup(self): - self.removeFile(Path.System('sssd.conf')) - - def write(self): - # Authconfig would not generate sssd in this case so we should not - # either. Even if --enablesssd[auth] was provided the configuration - # would not be generated. - if not self.getBool("ldap"): - return - - path = Path.Local("snippets/authconfig-sssd.conf") - config = ConfigSnippet(path, Path.System('sssd.conf')) - - schema = "rfc2307bis" if self.getBool("rfc2307bis") else None - - keys = { - 'ldap-uri': self.get("ldapserver"), - 'ldap-basedn': self.get("ldapbasedn"), - 'ldap-tls': self.getTrueOrNone("ldaptls"), - 'ldap-schema': schema, - 'krb5': self.getTrueOrNone("krb5"), - 'kdc-uri': self.get("krb5kdc"), - 'kpasswd-uri': self.get("krb5adminserver"), - 'realm': self.get("krb5realm"), - 'cache-creds': self.getTrueOrNone("cachecreds"), - 'cert-auth': self.getTrueOrNone("smartcard") - } - - config.write(keys) - os.chmod(Path.System('sssd.conf'), mode=0o600) - - class Winbind(Base): - def __init__(self, options): - super(Configuration.Winbind, self).__init__(options, ServiceName="winbind") - - def isEnabled(self): - if not self.isset("winbind") and not self.isset("winbindauth"): - return None - - return self.getBool("winbind") or self.getBool("winbindauth") - - def write(self): - if not self.isset("winbindjoin"): - return - - creds = self.options.get("winbindjoin").split("%", 1) - - user = creds[0] - password = None - if len(creds) > 1: - password = creds[1] + '\n' - - args = [ - 'join', - '-U', '"%s"' % user, - '--client-software', 'winbind' - ] - - if self.isset("smbworkgroup"): - args.append(self.get("smbworkgroup")) - - cmd = Command(Path.System('cmd-realm'), args, input=password) - try: - cmd.run() - except FileNotFoundError: - eprint(_("%s was not found. Please, install realmd.") - % Path.System('cmd-realm')) - - class PWQuality(Base): - def __init__(self, options): - super(Configuration.PWQuality, self).__init__(options) - - def write(self): - config = EnvironmentFile(Path.System('pwquality.conf')) - value_set = False - - pwopts = { - "minlen": self.get("passminlen"), - "minclass": self.get("passminclass"), - "maxrepeat": self.get("passmaxrepeat"), - "maxclassrepeat": self.get("passmaxclassrepeat"), - "lcredit": self.getBoolAsValue("reqlower", -1, 0, AllowNone=True), - "ucredit": self.getBoolAsValue("requpper", -1, 0, AllowNone=True), - "dcredit": self.getBoolAsValue("reqdigit", -1, 0, AllowNone=True), - "ocredit": self.getBoolAsValue("reqother", -1, 0, AllowNone=True) - } - - # Write options only if their are actually set - for opt, value in pwopts.items(): - if value is not None: - print(opt + "=" + str(value)) - config.set(opt, value) - value_set = True - - if value_set: - config.write() - - class MakeHomedir(Base): - def __init__(self, options): - super(Configuration.MakeHomedir, self).__init__(options, ServiceName="oddjobd") - - def isEnabled(self): - if not self.isset("mkhomedir"): - return None - - return self.getBool("mkhomedir") - - def disableService(self, nostop): - # Never disable the service in case it is already running as - # other applications may depend on it. - return - - class NIS(Base): - def __init__(self, options): - super(Configuration.NIS, self).__init__(options) - self.rpcbind = Service("rpcbind") - self.ypbind = Service("ypbind") - - def isEnabled(self): - if not self.isset("nis"): - return None - - return self.getBool("nis") - - def enableService(self, nostart): - if not self.isset("nisdomain"): - return - - nisdom = self.get("nisdomain") - - if not nostart: - cmd = Command(Path.System('cmd-domainname'), [nisdom]) - cmd.run() - - cmd = Command(Path.System('cmd-setsebool'), - ['-P', 'allow_ypbind', '1']) - cmd.run() - - self.rpcbind.enable() - self.ypbind.enable() - - if not nostart: - self.rpcbind.start(Restart=False) - self.ypbind.start() - - def disableService(self, nostop): - if not nostop: - cmd = Command(Path.System('cmd-domainname'), ["(none)"]) - cmd.run() - - cmd = Command(Path.System('cmd-setsebool'), - ['-P', 'allow_ypbind', '0']) - cmd.run() - - self.rpcbind.disable() - self.ypbind.disable() - - if not nostop: - self.rpcbind.stop() - self.ypbind.stop() - - def write(self): - if not self.isset("nisdomain"): - return - - output = "domain " + self.get("nisdomain") - - additional_servers = [] - if self.isset("nisserver"): - servers = self.get("nisserver").split(",") - additional_servers = servers[1:] - output += " server " + servers[0] + "\n" - else: - output += " broadcast\n" - - for server in additional_servers: - output += "ypserver " + server + "\n" - - filename = Path.System('yp.conf') - if self.getBool("test-call"): - print("========== BEGIN Content of [%s] ==========" % filename) - print(output) - print("========== END Content of [%s] ==========\n" % filename) - return - - with open(filename, "w") as f: - f.write(output) - - -class AuthCompat: - def __init__(self): - self.sysconfig = EnvironmentFile(Path.System('authconfig')) - self.options = Options() - - self.options.parse() - self.options.applysysconfig(self.sysconfig) - self.options.updatesysconfig(self.sysconfig) - - def printWarning(self): - print(_("Running authconfig compatibility tool.")) - print(_("The purpose of this tool is to enable authentication against " - "chosen services with authselect and minimum configuration. " - "It does not provide all capabilities of authconfig.\n")) - print(_("IMPORTANT: authconfig is replaced by authselect, " - "please update your scripts.")) - print(_("See Fedora 28 Change Page: https://fedoraproject.org/wiki/Changes/AuthselectAsDefault")) - print(_("See man authselect-migration(7) to help you with migration to authselect")) - - options = self.options.getSetButUnsupported() - if options: - print(_("Warning: These options are not supported anymore " - "and have no effect:")) - for name in options: - print(" --%s" % name) - - print("") - - def printOptions(self): - for option in Options.List: - print("%s=%s" % (option.name, option.value)) - - def printSysconfig(self): - for line in self.sysconfig.getall(): - print("%s=%s" % (line.name, line.value)) - - def canContinue(self): - disallowed = ["test", "probe", "restorebackup", "restorelastbackup"] - required = ["update", "updateall", "kickstart"] - - if not self.options.getBool("test") and os.getuid() != 0: - print(_("authconfig can only be run as root")) - return False - - for option in disallowed: - if self.options.getBool(option): - print(_("Error: option --%s is no longer supported and we " - "cannot continue if it is set." % option)) - return False - - if self.options.getBool("winbind") != self.options.getBool("winbindauth"): - print(_("Error: Both --enablewinbind and --enablewinbindauth must be set.")) - return False - - # We require one of these options to perform changes - # We encourage to use --updateall since we no longer support just pure - # --update or --kickstart, they will act as --updateall. - for option in required: - if self.options.getBool(option): - return True - - print(_("Error: Please, provide --updateall option.")) - return False - - def runAuthselect(self): - map = { - 'smartcard': 'with-smartcard', - 'requiresmartcard': 'with-smartcard-required', - 'fingerprint': 'with-fingerprint', - 'ecryptfs': 'with-ecryptfs', - 'mkhomedir': 'with-mkhomedir', - 'faillock': 'with-faillock', - 'pamaccess': 'with-pamaccess', - 'winbindkrb5': 'with-krb5' - } - - # Read current configuration first. - (profile, features) = self.getCurrentAuthselectConfig() - - # Change profile if requested. - if (self.options.getBool("ldap") - or self.options.getBool("ldapauth") - or self.options.getBool("sssd") - or self.options.getBool("sssdauth")): - profile = "sssd" - elif self.options.getBool("nis"): - profile = "nis" - elif self.options.getBool("winbind"): - profile = "winbind" - - # Default to sssd - if profile is None: - profile = "sssd" - - # Add enabled and remove disabled features. - for option, feature in map.items(): - if not self.options.isset(option): - continue - - enabled = self.options.getBool(option) - if enabled: - features.append(feature) - else: - while feature in features: - features.remove(feature) - - # Add lock-on-smartcard-removal if requested - if self.options.isset("smartcardaction"): - if int(self.options.get("smartcardaction")) == 0: - features.append("with-smartcard-lock-on-removal") - else: - features.remove("with-smartcard-lock-on-removal") - - # Remove duplicates. The order is not kept but that does not matter. - features = list(set(features)) - - # Always run with --force. This is either first call of authconfig - # in installation script or it is run on already configured system. - # We want to use authselect in both cases anyway, since authconfig - # would change the configuration either way. - args = ["select", profile] - args.extend(features) - args.append("--force") - - cmd = Command(Path.System('cmd-authselect'), args) - cmd.run() - - def getCurrentAuthselectConfig(self): - cmd = Command(Path.System('cmd-authselect'), ['check'], check=False) - cmd.run() - - if cmd.result is None or cmd.result.returncode != 0: - return (None, []) - - cmd = Command(Path.System('cmd-authselect'), ['current', '--raw']) - cmd.run() - - current = cmd.result.stdout.decode("utf-8").split() - return (current[0], current[1:]) - - def writeConfiguration(self): - configs = [ - Configuration.LDAP(self.options), - Configuration.Network(self.options), - Configuration.Kerberos(self.options), - Configuration.SSSD(self.options), - Configuration.Winbind(self.options), - Configuration.PWQuality(self.options), - Configuration.MakeHomedir(self.options), - Configuration.NIS(self.options) - ] - - for config in configs: - # Configuration decides if it needs to write something or not - config.write() - - # Enable or disable service if needed - nostart = self.options.getBool("nostart") - try: - enabled = config.isEnabled() - - # Skip service management if it can not be decided - if enabled is None: - continue - - if enabled: - config.enableService(nostart) - else: - config.disableService(nostart) - config.cleanup() - except subprocess.CalledProcessError as result: - # This is not fatal error. - eprint(_("Command [%s] failed with %d, stderr:") - % (' '.join(result.cmd), result.returncode)) - eprint(result.stderr.decode()) - - -def main(): - try: - locale.setlocale(locale.LC_ALL, '') - except locale.Error: - sys.stderr.write('Warning: Unsupported locale setting.\n') - - authcompat = AuthCompat() - authcompat.printWarning() - - Command.TEST = authcompat.options.getBool("test-call") - EnvironmentFile.TEST = authcompat.options.getBool("test-call") - ConfigSnippet.TEST = authcompat.options.getBool("test-call") - - if not authcompat.canContinue(): - sys.exit(1) - - try: - authcompat.runAuthselect() - authcompat.writeConfiguration() - authcompat.sysconfig.write() - except subprocess.CalledProcessError as result: - eprint(_("Command [%s] failed with %d, stderr:") - % (' '.join(result.cmd), result.returncode)) - eprint(result.stderr.decode()) - - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/src/compat/authcompat_ConfigSnippet.py b/src/compat/authcompat_ConfigSnippet.py deleted file mode 100644 index 01033ea0ab71e0eb235f03f1fb2a6aec124e2286..0000000000000000000000000000000000000000 --- a/src/compat/authcompat_ConfigSnippet.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Authors: -# Pavel Březina -# -# Copyright (C) 2018 Red Hat -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import errno -import os -import re - - -class ConfigSnippet: - TEST = False - - AllKeysRE = re.compile(r'\${\??(?P[\w-]*)}') - DummyKeysRE = re.compile(r'\${\?[\w-]*}') - - def __init__(self, template, destination): - with open(template, "r") as f: - self.template = f.read() - - self.destination = destination - - def generate(self, values): - # First remove lines containing key that is not set - lines = self.template.split('\n') - remove = [] - - for idx, line in enumerate(lines): - for match in self.AllKeysRE.finditer(line): - key = match.group("key") - if key not in values or values[key] is None: - remove.append(idx) - break - - for idx in sorted(remove, reverse=True): - del lines[idx] - - # Build output string - output = '\n'.join(lines) - - # Remove all dummy keys ${?key} - output = self.DummyKeysRE.sub("", output) - - # Replace values - for key, value in values.items(): - if value is None: - continue - - if type(value) is bool: - value = "true" if value else "false" - - output = output.replace("${%s}" % key, value) - - return output - - def write(self, values, to_stdout=False): - output = self.generate(values) - - if self.TEST: - print("========== BEGIN Content of [%s] ==========" % self.destination) - print(output) - print("========== END Content of [%s] ==========\n" % self.destination) - return - - dirname = os.path.dirname(self.destination) - if not os.path.exists(dirname): - try: - os.makedirs(dirname) - except OSError as exception: - if exception.errno == errno.EEXIST and os.path.isdir(dirname): - pass - else: - raise - - with open(self.destination, "w") as f: - f.write(output) diff --git a/src/compat/authcompat_EnvironmentFile.py b/src/compat/authcompat_EnvironmentFile.py deleted file mode 100644 index 2dabd5963ce1aa7160801415f3bf69d4a793cdd1..0000000000000000000000000000000000000000 --- a/src/compat/authcompat_EnvironmentFile.py +++ /dev/null @@ -1,216 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Authors: -# Pavel Březina -# -# Copyright (C) 2018 Red Hat -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import errno -import os -import re - - -class EnvironmentFile: - TEST = False - - def __init__(self, filename, - delimiter='=', delimiter_re=None, - quotes=True): - self.filename = filename - self.delimiter = delimiter - self.quotes = quotes - self.environment = [] - - delimiter_re = delimiter_re if delimiter_re is not None else delimiter - self.pattern = re.compile(r'^(\s*)(\S*)([^\n\S]*)(' - + delimiter_re - + r')([^\n\S]*)(.*)$', - re.MULTILINE) - - self.read() - - def read(self): - try: - with open(self.filename, "r") as f: - lines = f.readlines() - except FileNotFoundError: - return - - for line in lines: - parsed = self.Line.Parse(line, self.pattern, - self.delimiter, self.quotes) - self.environment.append(parsed) - - def write(self): - output = "" - for line in self.environment: - output = output + line.getLine() - - if self.TEST: - print("========== BEGIN Content of [%s] ==========" % self.filename) - print(output) - print("========== END Content of [%s] ==========\n" % self.filename) - return - - dirname = os.path.dirname(self.filename) - if not os.path.exists(dirname): - try: - os.makedirs(dirname) - except OSError as exception: - if exception.errno == errno.EEXIST and os.path.isdir(dirname): - pass - else: - raise - - with open(self.filename, "w") as f: - f.write(output) - - def get(self, name, default=None): - value = None - for line in self.environment: - if line.isVariable() and line.name == name: - value = line.value - - if value is None: - return default - - if value.lower() in [None, "no", "false", "f", "n"]: - return False - elif value.lower() in ["yes", "true", "t", "y"]: - return True - - return value - - def getall(self): - lines = [] - for line in self.environment: - if line.isVariable(): - lines.append(line) - - return lines - - def set(self, name, value): - if type(value) is bool: - value = "yes" if value else "no" - - for line in self.environment: - if line.isVariable() and line.name == name: - line.set(name, value) - return - - line = self.Line(self.delimiter, self.quotes) - line.set(name, value) - self.environment.append(line) - - class Line: - def __init__(self, delimiter, quotes, - name=None, value=None, original=None, fmt=None): - self.delimiter = delimiter - self.quotes = quotes - self.name = name - self.value = value - self.original = original - self.fmt = fmt - - def isVariable(self): - return self.fmt is not None - - def isOriginal(self): - return self.original is not None - - def set(self, name, value): - self.name = name - self.value = value - if self.fmt is None: - self.fmt = "${name}%s${value}\n" % self.delimiter - - def getLine(self): - if self.isOriginal(): - return self.original - - value = self.value if self.value is not None else "" - replacement = { - 'name': self.name, - 'value': self.Escape(value, self.quotes) - } - - line = self.fmt - for key, value in replacement.items(): - line = line.replace("${" + key + "}", str(value)) - - return line - - @staticmethod - def Parse(line, pattern, delimiter, quotes): - match = pattern.match(line) - if line.startswith('#') or not line.strip() or not match: - return EnvironmentFile.Line(delimiter, quotes, original=line) - - name = match.group(2) - value = EnvironmentFile.Line.Unescape(match.group(6), quotes) - fmt = "%s${name}%s%s%s${value}\n" % (match.group(1), - match.group(3), - match.group(4), - match.group(5)) - - return EnvironmentFile.Line(delimiter, quotes, name=name, - value=value, fmt=fmt) - - @staticmethod - def Escape(value, quotes): - if value is None: - return "" - - value = str(value) - value = value.replace("\\", "\\\\") - value = value.replace("\"", "\\\"") - value = value.replace("'", "\\\'") - value = value.replace("$", "\\$") - value = value.replace("~", "\\~") - value = value.replace("`", "\\`") - - if quotes: - if value.find(" ") > 0 or value.find("\t") > 0: - value = "\"" + value + "\"" - - return value - - @staticmethod - def Unescape(value, quotes): - if not value: - return value - - value = str(value) - - length = len(value) - if quotes: - if (value[0] == "\"" or value[0] == "'") and value[0] == value[length - 1]: - value = value[1:length - 1] - - i = 0 - while True: - i = value.find("\\", i) - if i < 0: - break - if i + 1 >= len(value): - value = value[0:i] - break - - value = value[0:i] + value[i + 1:] - i += 1 - - return value diff --git a/src/compat/authcompat_Options.py b/src/compat/authcompat_Options.py deleted file mode 100644 index d26dedabdfb9519861076b58cddd0dd0eb04b7cb..0000000000000000000000000000000000000000 --- a/src/compat/authcompat_Options.py +++ /dev/null @@ -1,326 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Authors: -# Pavel Březina -# -# Copyright (C) 2018 Red Hat -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for morerequi details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import argparse -import gettext - -_ = gettext.gettext - - -class Option: - def __init__(self, name, metavar, help, feature, supported): - self.name = name - self.metavar = metavar - self.help = help - self.feature = feature - self.supported = supported - self.value = None - self.from_sysconfig = False - - def set(self, new_value): - self.value = new_value - - def set_from_sysconfig(self, new_value): - self.set(new_value) - self.from_sysconfig = True - - def isset(self): - return self.value is not None - - @staticmethod - def Valued(name, metavar, help): - return Option(name, metavar, help, feature=False, supported=True) - - @staticmethod - def Switch(name, help): - return Option(name, None, help, feature=False, supported=True) - - @staticmethod - def Feature(name, help): - return Option(name, None, help, feature=True, supported=True) - - @staticmethod - def UnsupportedValued(name, metavar): - return Option(name, metavar, None, feature=False, supported=False) - - @staticmethod - def UnsupportedFeature(name): - return Option(name, None, None, feature=True, supported=False) - - @staticmethod - def UnsupportedSwitch(name): - return Option(name, None, None, feature=False, supported=False) - - -class Options: - List = [ - # These options are still supported in authconfig compatibility - # layers. The tool will do its best to translate them to authselect - # call and where needed, it will generate a configuration file. - # - # However, they will just make sure that an authentication against - # expected service is working. They may not result in the exact same - # configuration as authconfig would generate. - Option.Feature("nis", _("NIS for user information by default")), - Option.Valued("nisdomain", _(""), _("default NIS domain")), - Option.Valued("nisserver", _(""), _("default NIS server")), - Option.Feature("ldap", _("LDAP for user information by default")), - Option.Feature("ldapauth", _("LDAP for authentication by default")), - Option.Valued("ldapserver", _(""), _("default LDAP server hostname or URI")), - Option.Valued("ldapbasedn", _(""), _("default LDAP base DN")), - Option.Feature("ldaptls", _("use of TLS with LDAP (RFC-2830)")), - Option.Feature("ldapstarttls", _("use of TLS for identity lookups with LDAP (RFC-2830)")), - Option.Feature("rfc2307bis", _("use of RFC-2307bis schema for LDAP user information lookups")), - Option.Feature("smartcard", _("authentication with smart card by default")), - Option.Valued("smartcardaction", _("<0=Lock|1=Ignore>"), _("action to be taken on smart card removal")), - Option.Feature("requiresmartcard", _("require smart card for authentication by default")), - Option.Feature("fingerprint", _("authentication with fingerprint readers by default")), - Option.Feature("ecryptfs", _("automatic per-user ecryptfs")), - Option.Feature("krb5", _("Kerberos authentication by default")), - Option.Valued("krb5kdc", _(""), _("default Kerberos KDC")), - Option.Valued("krb5adminserver", _(""), _("default Kerberos admin server")), - Option.Valued("krb5realm", _(""), _("default Kerberos realm")), - Option.Feature("krb5kdcdns", _("use of DNS to find Kerberos KDCs")), - Option.Feature("krb5realmdns", _("use of DNS to find Kerberos realms")), - Option.Feature("winbind", _("winbind for user information by default")), - Option.Feature("winbindauth", _("winbind for authentication by default")), - Option.Valued("winbindjoin", _(""), _("join the winbind domain or ads realm now as this administrator")), - Option.Feature("winbindkrb5", _("Kerberos 5 for authenticate with winbind")), - Option.Valued("smbworkgroup", _(""), _("workgroup authentication servers are in")), - Option.Feature("sssd", _("SSSD for user information by default with manually managed configuration")), - Option.Feature("sssdauth", _("SSSD for authentication by default with manually managed configuration")), - Option.Feature("cachecreds", _("caching of user credentials in SSSD by default")), - Option.Feature("pamaccess", _("check of access.conf during account authorization")), - Option.Feature("mkhomedir", _("creation of home directories for users on their first login")), - Option.Feature("faillock", _("account locking in case of too many consecutive authentication failures")), - Option.Valued("passminlen", _(""), _("minimum length of a password")), - Option.Valued("passminclass", _(""), _("minimum number of character classes in a password")), - Option.Valued("passmaxrepeat", _(""), _("maximum number of same consecutive characters in a password")), - Option.Valued("passmaxclassrepeat", _(""), _("maximum number of consecutive characters of same class in a password")), - Option.Feature("reqlower", _("require at least one lowercase character in a password")), - Option.Feature("requpper", _("require at least one uppercase character in a password")), - Option.Feature("reqdigit", _("require at least one digit in a password")), - Option.Feature("reqother", _("require at least one other character in a password")), - - # Program options - Option.Switch("nostart", _("do not start/stop services")), - Option.Switch("updateall", _("update all configuration files")), - Option.Switch("update", _("the same as --updateall")), - Option.Switch("kickstart", _("the same as --updateall")), - - # Hidden compat tool option, useful for testing. No changes to the - # system will be done, they will be printed. - Option.Switch("test-call", argparse.SUPPRESS), - - # Unsupported program options but we have to react somehow when set - Option.UnsupportedSwitch("test"), - Option.UnsupportedSwitch("probe"), - Option.UnsupportedValued("savebackup", _("")), - Option.UnsupportedValued("restorebackup", _("")), - Option.UnsupportedSwitch("restorelastbackup"), - - # These options are no longer supported in authconfig compatibility - # layers and will produce warning when used. They will not affect - # the system. - Option.UnsupportedFeature("cache"), - Option.UnsupportedFeature("shadow"), - Option.UnsupportedSwitch("useshadow"), - Option.UnsupportedFeature("md5"), - Option.UnsupportedSwitch("usemd5"), - Option.UnsupportedValued("passalgo", _("")), - Option.UnsupportedValued("ldaploadcacert", _("")), - Option.UnsupportedValued("smartcardmodule", _("")), - Option.UnsupportedValued("smbsecurity", _("")), - Option.UnsupportedValued("smbrealm", _("")), - Option.UnsupportedValued("smbservers", _("")), - Option.UnsupportedValued("smbidmaprange", _("")), - Option.UnsupportedValued("smbidmapuid", _("")), - Option.UnsupportedValued("smbidmapgid", _("")), - Option.UnsupportedValued("winbindseparator", _("<\\>")), - Option.UnsupportedValued("winbindtemplatehomedir", _("")), - Option.UnsupportedValued("winbindtemplateshell", _("")), - Option.UnsupportedFeature("winbindusedefaultdomain"), - Option.UnsupportedFeature("winbindoffline"), - Option.UnsupportedFeature("preferdns"), - Option.UnsupportedFeature("forcelegacy"), - Option.UnsupportedFeature("locauthorize"), - Option.UnsupportedFeature("sysnetauth"), - Option.UnsupportedValued("faillockargs", _("")), - ] - - Map = { - # These options were use with autodetection of pam_cracklib - # and pam_passwdqc. However, authselect supports only pam_pwquality. - # "USEPWQUALITY" : "", - # "USEPASSWDQC" : "", - "USEFAILLOCK": "faillock", - "FAILLOCKARGS": "faillockargs", - "USELDAP": "ldap", - "USENIS": "nis", - "USEECRYPTFS": "ecryptfs", - "USEWINBIND": "winbind", - "WINBINDKRB5": "winbindkrb5", - "USESSSD": "sssd", - "USEKERBEROS": "krb5", - "USELDAPAUTH": "ldapauth", - "USESMARTCARD": "smartcard", - "FORCESMARTCARD": "requiresmartcard", - "USEFPRINTD": "fingerprint", - "PASSWDALGORITHM": "passalgo", - "USEMD5": "md5", - "USESHADOW": "shadow", - "USEWINBINDAUTH": "winbindauth", - "USESSSDAUTH": "sssdauth", - "USELOCAUTHORIZE": "locauthorize", - "USEPAMACCESS": "pamaccess", - "USEMKHOMEDIR": "mkhomedir", - "USESYSNETAUTH": "sysnetauth", - "FORCELEGACY": "forcelegacy", - "CACHECREDENTIALS": "cachecreds", - } - - def __init__(self): - self.options = {} - - for option in self.List: - self.options[option.name] = option - - def parse(self): - parser = argparse.ArgumentParser(description='Authconfig Compatibility Tool.') - - parsers = { - 'supported': parser.add_argument_group(_('These options have a compatibility layer')), - 'unsupported': parser.add_argument_group(_('These options are no longer supported and have no effect')) - } - - for option in self.List: - group = 'supported' if option.supported else 'unsupported' - self.add_option(parsers[group], option) - - cmdline = parser.parse_args() - - for name, option in self.options.items(): - value = getattr(cmdline, name) - option.set(value) - - # usemd5 and useshadow are equivalent to enablemd5 and enableshadow - if not self.isset('md5') and self.isset('usemd5'): - self.set('md5', self.get('usemd5')) - - if not self.isset('shadow') and self.isset('useshadow'): - self.set('shadow', self.get('useshadow')) - - # ldapstarttls is equivalent to ldaptls - if self.isset('ldapstarttls') and not self.isset('ldaptls'): - self.set('ldaptls', self.get('ldapstarttls')) - - def applysysconfig(self, sysconfig): - for name, option in self.Map.items(): - if not self.isset(option): - self.options[option].set_from_sysconfig(sysconfig.get(name)) - - def updatesysconfig(self, sysconfig): - for name, option in self.Map.items(): - if self.isset(option): - sysconfig.set(name, self.get(option)) - - def get(self, name): - return self.options[name].value - - def set(self, name, value): - self.options[name].set(value) - - def isset(self, name): - return self.options[name].isset() - - def getBool(self, name): - value = self.get(name) - if value is None or not value: - return False - return True - - def getTrueOrNone(self, name): - value = self.get(name) - if value is None or not value: - return None - return True - - def getSetButUnsupported(self): - options = [] - for option in Options.List: - if option.supported: - continue - - if not option.isset(): - continue - - if option.from_sysconfig: - continue - - name = option.name - if option.feature: - name = "enable" + name if option.value else "disable" + name - - options.append(name) - - return options - - def add_option(self, parser, option): - if option.metavar is not None: - self.add_valued(parser, option) - elif option.feature: - self.add_feature(parser, option) - else: - self.add_switch(parser, option) - - def add_valued(self, parser, option): - parser.add_argument("--" + option.name, - action='store', - help=option.help, - dest=option.name, - metavar=option.metavar) - - def add_switch(self, parser, option): - parser.add_argument("--" + option.name, - action='store_const', - const=True, - help=option.help, - dest=option.name) - - def add_feature(self, parser, option): - help_enable = None - help_disable = None - - if option.help is not None: - help_enable = _("enable") + " " + option.help - help_disable = _("disable") + " " + option.help - - parser.add_argument("--enable" + option.name, - action='store_const', - const=True, - help=help_enable, - dest=option.name) - - parser.add_argument("--disable" + option.name, - action='store_const', - const=False, - help=help_disable, - dest=option.name) diff --git a/src/compat/snippets/authconfig-krb.conf b/src/compat/snippets/authconfig-krb.conf deleted file mode 100644 index e5ace8626321795c009ed9c0050cd35cab6a8ee0..0000000000000000000000000000000000000000 --- a/src/compat/snippets/authconfig-krb.conf +++ /dev/null @@ -1,14 +0,0 @@ -[libdefaults] - dns_lookup_kdc = ${kdc-srv} - dns_lookup_realm = ${realm-srv} - default_realm = ${realm} - -[realms] - ${realm} = { - kdc = ${kdc} - admin_server = ${adminserver} - ${?realm}} - -[domain_realm] - ${domain} = ${realm} - .${domain} = ${realm} diff --git a/src/compat/snippets/authconfig-sssd.conf b/src/compat/snippets/authconfig-sssd.conf deleted file mode 100644 index 13bd1dcb84c0b4a983d19dc00d8a73e4c7c2cee4..0000000000000000000000000000000000000000 --- a/src/compat/snippets/authconfig-sssd.conf +++ /dev/null @@ -1,18 +0,0 @@ -[sssd] -domains = default - -[domain/default] -id_provider = ldap -auth_provider${?krb5} = krb5 -ldap_uri = ${ldap-uri} -ldap_search_base = ${ldap-basedn} -ldap_id_use_start_tls = ${ldap-tls} -ldap_schema = ${ldap-schema} -krb5_server${?krb5} = ${kdc-uri} -krb5_kpasswd${?krb5} = ${kpasswd-uri} -krb5_realm${?krb5} = ${realm} -krb5_store_password_if_offline${?krb5} = ${cache-credentials} -cache_credentials = ${cache-credentials} - -[pam]${?cert-auth} -pam_cert_auth = ${cert-auth} diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 index ae8fa0274e038e98115d000717487dbdbc04df4c..8dafd94cf57398ce1c654d83289d210ac730d14d 100644 --- a/src/conf_macros.m4 +++ b/src/conf_macros.m4 @@ -81,15 +81,6 @@ AS_IF([test "x$enable_debug_template_regex" = "xyes"], ) ) -AC_ARG_WITH([compat], - [AC_HELP_STRING([--with-compat], [Build with compatibility tool [no]])], - [], with_compat=no -) -if test x"$with_compat" = xyes; then - AM_PATH_PYTHON([3]) -fi -AM_CONDITIONAL([BUILD_COMPAT], [test x$with_compat = xyes]) - AC_ARG_WITH([nis-profile], [AC_HELP_STRING([--with-nis-profile], [Install NIS profile [no]])], [], with_nis_profile=no -- 2.42.0