Merge branch 'recursive-tag-fix' of https://github.com/kwirk/fail2ban

* 'recursive-tag-fix' of https://github.com/kwirk/fail2ban:
  ENH: explicitly define tags which should be escaped
  DOC: ChangeLog update for recursive tag bug fix
  BF: Tags not fully recursively substituted

Conflicts:
	ChangeLog -- kept all as is
pull/661/merge
Yaroslav Halchenko 2014-05-13 11:23:30 -04:00
commit 2526dbae92
3 changed files with 26 additions and 8 deletions

View File

@ -25,6 +25,8 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
* Fix actions failing to execute for Python 3.4.0. Workaround for * Fix actions failing to execute for Python 3.4.0. Workaround for
http://bugs.python.org/issue21207 http://bugs.python.org/issue21207
* Database now returns persistent bans on restart (bantime < 0) * Database now returns persistent bans on restart (bantime < 0)
* Recursive action tags now fully processed. Fixes issue with bsd-ipfw
action
- New features: - New features:
- Added monit filter thanks Jason H Martin. - Added monit filter thanks Jason H Martin.

View File

@ -194,6 +194,8 @@ class CommandAction(ActionBase):
timeout timeout
""" """
_escapedTags = set(('matches', 'ipmatches', 'ipjailmatches'))
def __init__(self, jail, name): def __init__(self, jail, name):
super(CommandAction, self).__init__(jail, name) super(CommandAction, self).__init__(jail, name)
self.timeout = 60 self.timeout = 60
@ -351,8 +353,8 @@ class CommandAction(ActionBase):
if not self.executeCmd(stopCmd, self.timeout): if not self.executeCmd(stopCmd, self.timeout):
raise RuntimeError("Error stopping action") raise RuntimeError("Error stopping action")
@staticmethod @classmethod
def substituteRecursiveTags(tags): def substituteRecursiveTags(cls, tags):
"""Sort out tag definitions within other tags. """Sort out tag definitions within other tags.
so: becomes: so: becomes:
@ -371,8 +373,11 @@ class CommandAction(ActionBase):
within the values recursively replaced. within the values recursively replaced.
""" """
t = re.compile(r'<([^ >]+)>') t = re.compile(r'<([^ >]+)>')
for tag, value in tags.iteritems(): for tag in tags.iterkeys():
value = str(value) if tag in cls._escapedTags:
# Escaped so won't match
continue
value = str(tags[tag])
m = t.search(value) m = t.search(value)
done = [] done = []
#logSys.log(5, 'TAG: %s, value: %s' % (tag, value)) #logSys.log(5, 'TAG: %s, value: %s' % (tag, value))
@ -383,6 +388,9 @@ class CommandAction(ActionBase):
# recursive definitions are bad # recursive definitions are bad
#logSys.log(5, 'recursion fail tag: %s value: %s' % (tag, value) ) #logSys.log(5, 'recursion fail tag: %s value: %s' % (tag, value) )
return False return False
elif found_tag in cls._escapedTags:
# Escaped so won't match
continue
else: else:
if tags.has_key(found_tag): if tags.has_key(found_tag):
value = value.replace('<%s>' % found_tag , tags[found_tag]) value = value.replace('<%s>' % found_tag , tags[found_tag])
@ -441,10 +449,11 @@ class CommandAction(ActionBase):
`query` string with tags replaced. `query` string with tags replaced.
""" """
string = query string = query
aInfo = cls.substituteRecursiveTags(aInfo)
for tag in aInfo: for tag in aInfo:
if "<%s>" % tag in query: if "<%s>" % tag in query:
value = str(aInfo[tag]) # assure string value = str(aInfo[tag]) # assure string
if tag.endswith('matches'): if tag in cls._escapedTags:
# That one needs to be escaped since its content is # That one needs to be escaped since its content is
# out of our control # out of our control
value = cls.escapeTag(value) value = cls.escapeTag(value)

View File

@ -100,17 +100,24 @@ class CommandActionTest(LogCaptureTestCase):
{'ipjailmatches': "some >char< should \< be[ escap}ed&\n"}), {'ipjailmatches': "some >char< should \< be[ escap}ed&\n"}),
"some \\>char\\< should \\\\\\< be\\[ escap\\}ed\\&\n") "some \\>char\\< should \\\\\\< be\\[ escap\\}ed\\&\n")
# Recursive
aInfo["ABC"] = "<xyz>"
self.assertEqual(
self.__action.replaceTag("Text <xyz> text <ABC> ABC", aInfo),
"Text 890 text 890 ABC")
# Callable # Callable
self.assertEqual( self.assertEqual(
self.__action.replaceTag("09 <callme> 11", self.__action.replaceTag("09 <matches> 11",
CallingMap(callme=lambda: str(10))), CallingMap(matches=lambda: str(10))),
"09 10 11") "09 10 11")
# As tag not present, therefore callable should not be called # As tag not present, therefore callable should not be called
# Will raise ValueError if it is # Will raise ValueError if it is
self.assertEqual( self.assertEqual(
self.__action.replaceTag("abc", self.__action.replaceTag("abc",
CallingMap(callme=lambda: int("a"))), "abc") CallingMap(matches=lambda: int("a"))), "abc")
def testExecuteActionBan(self): def testExecuteActionBan(self):
self.__action.actionstart = "touch /tmp/fail2ban.test" self.__action.actionstart = "touch /tmp/fail2ban.test"