From d02a613e890bc2a5c7c969d66c1d4f4d95ed3a9b Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 19 Mar 2025 02:19:16 +0100 Subject: [PATCH] configreaders: don't swallow return code by decoding error (whole jail or fail2ban config failed to read due to some error like encoding etc), so dump or test of config would get an error at end (and coverage for #3971) --- fail2ban/client/configreader.py | 1 + fail2ban/client/configurator.py | 6 ++++-- fail2ban/client/fail2banreader.py | 2 +- fail2ban/tests/fail2banclienttestcase.py | 17 +++++++++++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/fail2ban/client/configreader.py b/fail2ban/client/configreader.py index 71dce228..630ef32f 100644 --- a/fail2ban/client/configreader.py +++ b/fail2ban/client/configreader.py @@ -230,6 +230,7 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes): missed = [ cf for cf in config_files if cf not in config_files_read ] if missed: logSys.error("Could not read config files: %s", ', '.join(missed)) + return False if config_files_read: return True logSys.error("Found no accessible config files for %r under %s", diff --git a/fail2ban/client/configurator.py b/fail2ban/client/configurator.py index fe735251..4e73e378 100644 --- a/fail2ban/client/configurator.py +++ b/fail2ban/client/configurator.py @@ -63,11 +63,13 @@ class Configurator: return fail2ban_basedir def readEarly(self): - self.__fail2ban.read() + if not self.__fail2ban.read(): + raise LookupError("Read fail2ban configuration failed.") def readAll(self): self.readEarly() - self.__jails.read() + if not self.__jails.read(): + raise LookupError("Read jails configuration failed.") def getEarlyOptions(self): return self.__fail2ban.getEarlyOptions() diff --git a/fail2ban/client/fail2banreader.py b/fail2ban/client/fail2banreader.py index 1f135cf8..19026d90 100644 --- a/fail2ban/client/fail2banreader.py +++ b/fail2ban/client/fail2banreader.py @@ -37,7 +37,7 @@ class Fail2banReader(ConfigReader): ConfigReader.__init__(self, **kwargs) def read(self): - ConfigReader.read(self, "fail2ban") + return ConfigReader.read(self, "fail2ban") def getEarlyOptions(self): opts = [ diff --git a/fail2ban/tests/fail2banclienttestcase.py b/fail2ban/tests/fail2banclienttestcase.py index 28b908cd..b3509739 100644 --- a/fail2ban/tests/fail2banclienttestcase.py +++ b/fail2ban/tests/fail2banclienttestcase.py @@ -826,6 +826,23 @@ class Fail2banServerTest(Fail2banClientServerBase): "Errors in jail 'broken-jail'.", "ERROR: test configuration failed", all=True) + # disable jail in .local (shall be again OK): + self.pruneLog("[test-phase 1]") + _write_file(pjoin(cfg, "jail.local"), "a", "", + "[broken-jail]", "enabled = false") + self.execCmd(SUCCESS, startparams, "--test") + self.assertLogged("OK: configuration test is successful") + + # generate decoding error: ('utf-8' codec can't decode byte 0xfd): + self.pruneLog("[test-phase 1a]") + with open(pjoin(cfg, "jail.local"), "ab") as f: + f.write(b"\n# invalid char \xfd") + self.execCmd(FAILED, startparams, "-t") + self.assertLogged("Could not read config files", + "Read jails configuration failed.", + "ERROR: test configuration failed", all=True) + + @with_tmpdir def testKillAfterStart(self, tmp): try: