From ca4da9d1d3f792562500182711abc149b2c741a1 Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 11 Nov 2020 11:08:23 +0100 Subject: [PATCH] actions: extend tags replacement in non ticket-based commands (actionstart, actionstop, etc); fixes regression by interpolation of tag `` introduced in 0.11 with dynamic bantime (due to `bantime.increment`, see #2869) --- fail2ban/server/action.py | 13 ++++++++++++- fail2ban/server/actions.py | 12 +++++++----- fail2ban/tests/servertestcase.py | 3 ++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/fail2ban/server/action.py b/fail2ban/server/action.py index 1c313cf0..f52e0878 100644 --- a/fail2ban/server/action.py +++ b/fail2ban/server/action.py @@ -455,7 +455,18 @@ class CommandAction(ActionBase): ret = True # avoid double execution of same command for both families: if cmd and cmd not in self._operationExecuted(tag, lambda f: f != famoper): - ret = self.executeCmd(cmd, self.timeout) + realCmd = cmd + if self._jail: + # simulate action info with "empty" ticket: + aInfo = getattr(self._jail.actions, 'actionInfo', None) + if not aInfo: + aInfo = self._jail.actions._getActionInfo(None) + setattr(self._jail.actions, 'actionInfo', aInfo) + aInfo['time'] = MyTime.time() + aInfo['family'] = famoper + # replace dynamical tags, important - don't cache, no recursion and auto-escape here + realCmd = self.replaceDynamicTags(cmd, aInfo) + ret = self.executeCmd(realCmd, self.timeout) res &= ret if afterExec: afterExec(famoper, ret) self._operationExecuted(tag, famoper, cmd if ret else None) diff --git a/fail2ban/server/actions.py b/fail2ban/server/actions.py index 49db5df7..967908af 100644 --- a/fail2ban/server/actions.py +++ b/fail2ban/server/actions.py @@ -457,7 +457,9 @@ class Actions(JailThread, Mapping): return mi[idx] if mi[idx] is not None else self.__ticket - def __getActionInfo(self, ticket): + def _getActionInfo(self, ticket): + if not ticket: + ticket = BanTicket("", MyTime.time()) aInfo = Actions.ActionInfo(ticket, self._jail) return aInfo @@ -491,7 +493,7 @@ class Actions(JailThread, Mapping): bTicket = BanTicket.wrap(ticket) btime = ticket.getBanTime(self.__banManager.getBanTime()) ip = bTicket.getIP() - aInfo = self.__getActionInfo(bTicket) + aInfo = self._getActionInfo(bTicket) reason = {} if self.__banManager.addBanTicket(bTicket, reason=reason): cnt += 1 @@ -568,7 +570,7 @@ class Actions(JailThread, Mapping): """ actions = actions or self._actions ip = ticket.getIP() - aInfo = self.__getActionInfo(ticket) + aInfo = self._getActionInfo(ticket) if log: logSys.notice("[%s] Reban %s%s", self._jail.name, aInfo["ip"], (', action %r' % actions.keys()[0] if len(actions) == 1 else '')) for name, action in actions.iteritems(): @@ -602,7 +604,7 @@ class Actions(JailThread, Mapping): if not action._prolongable: continue if aInfo is None: - aInfo = self.__getActionInfo(ticket) + aInfo = self._getActionInfo(ticket) if not aInfo.immutable: aInfo.reset() action.prolong(aInfo) except Exception as e: @@ -696,7 +698,7 @@ class Actions(JailThread, Mapping): else: unbactions = actions ip = ticket.getIP() - aInfo = self.__getActionInfo(ticket) + aInfo = self._getActionInfo(ticket) if log: logSys.notice("[%s] Unban %s", self._jail.name, aInfo["ip"]) for name, action in unbactions.iteritems(): diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 3bd4501b..d2bf8bdc 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -1448,9 +1448,10 @@ class ServerConfigReaderTests(LogCaptureTestCase): ), }), # dummy -- - ('j-dummy', 'dummy[name=%(__name__)s, init="==", target="/tmp/fail2ban.dummy"]', { + ('j-dummy', '''dummy[name=%(__name__)s, init="=='/'==bt:==bc:==", target="/tmp/fail2ban.dummy"]''', { 'ip4': ('family: inet4',), 'ip6': ('family: inet6',), 'start': ( + '''`printf %b "=='/'==bt:600==bc:0==\\n"''', ## empty family (independent in this action, same for both), no ip on start, initial bantime and bancount '`echo "[j-dummy] dummy /tmp/fail2ban.dummy -- started"`', ), 'flush': (