You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1511 lines
53 KiB
1511 lines
53 KiB
From 3687d4e28a45b1896165e2e1d029fc81bf5a2a11 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
|
|
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 <pbrezina@redhat.com>
|
|
-#
|
|
-# 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 <http://www.gnu.org/licenses/>.
|
|
-#
|
|
-
|
|
-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 <pbrezina@redhat.com>
|
|
-#
|
|
-# 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 <http://www.gnu.org/licenses/>.
|
|
-#
|
|
-
|
|
-import errno
|
|
-import os
|
|
-import re
|
|
-
|
|
-
|
|
-class ConfigSnippet:
|
|
- TEST = False
|
|
-
|
|
- AllKeysRE = re.compile(r'\${\??(?P<key>[\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 <pbrezina@redhat.com>
|
|
-#
|
|
-# 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 <http://www.gnu.org/licenses/>.
|
|
-#
|
|
-
|
|
-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 <pbrezina@redhat.com>
|
|
-#
|
|
-# 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 <http://www.gnu.org/licenses/>.
|
|
-#
|
|
-
|
|
-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", _("<domain>"), _("default NIS domain")),
|
|
- Option.Valued("nisserver", _("<server>"), _("default NIS server")),
|
|
- Option.Feature("ldap", _("LDAP for user information by default")),
|
|
- Option.Feature("ldapauth", _("LDAP for authentication by default")),
|
|
- Option.Valued("ldapserver", _("<server>"), _("default LDAP server hostname or URI")),
|
|
- Option.Valued("ldapbasedn", _("<dn>"), _("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", _("<server>"), _("default Kerberos KDC")),
|
|
- Option.Valued("krb5adminserver", _("<server>"), _("default Kerberos admin server")),
|
|
- Option.Valued("krb5realm", _("<realm>"), _("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", _("<Administrator>"), _("join the winbind domain or ads realm now as this administrator")),
|
|
- Option.Feature("winbindkrb5", _("Kerberos 5 for authenticate with winbind")),
|
|
- Option.Valued("smbworkgroup", _("<workgroup>"), _("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", _("<number>"), _("minimum length of a password")),
|
|
- Option.Valued("passminclass", _("<number>"), _("minimum number of character classes in a password")),
|
|
- Option.Valued("passmaxrepeat", _("<number>"), _("maximum number of same consecutive characters in a password")),
|
|
- Option.Valued("passmaxclassrepeat", _("<number>"), _("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", _("<name>")),
|
|
- Option.UnsupportedValued("restorebackup", _("<name>")),
|
|
- 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", _("<descrypt|bigcrypt|md5|sha256|sha512|yescrypt>")),
|
|
- Option.UnsupportedValued("ldaploadcacert", _("<URL>")),
|
|
- Option.UnsupportedValued("smartcardmodule", _("<module>")),
|
|
- Option.UnsupportedValued("smbsecurity", _("<user|server|domain|ads>")),
|
|
- Option.UnsupportedValued("smbrealm", _("<realm>")),
|
|
- Option.UnsupportedValued("smbservers", _("<servers>")),
|
|
- Option.UnsupportedValued("smbidmaprange", _("<lowest-highest>")),
|
|
- Option.UnsupportedValued("smbidmapuid", _("<lowest-highest>")),
|
|
- Option.UnsupportedValued("smbidmapgid", _("<lowest-highest>")),
|
|
- Option.UnsupportedValued("winbindseparator", _("<\\>")),
|
|
- Option.UnsupportedValued("winbindtemplatehomedir", _("</home/%D/%U>")),
|
|
- Option.UnsupportedValued("winbindtemplateshell", _("</bin/false>")),
|
|
- Option.UnsupportedFeature("winbindusedefaultdomain"),
|
|
- Option.UnsupportedFeature("winbindoffline"),
|
|
- Option.UnsupportedFeature("preferdns"),
|
|
- Option.UnsupportedFeature("forcelegacy"),
|
|
- Option.UnsupportedFeature("locauthorize"),
|
|
- Option.UnsupportedFeature("sysnetauth"),
|
|
- Option.UnsupportedValued("faillockargs", _("<options>")),
|
|
- ]
|
|
-
|
|
- 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
|
|
|