summaryrefslogtreecommitdiff
path: root/fail2ban/helpers.py
diff options
context:
space:
mode:
authorsebres <serg.brester@sebres.de>2017-02-16 16:00:24 +0100
committersebres <serg.brester@sebres.de>2017-02-16 16:01:10 +0100
commita6318b159b0c2db5405aa525882e208aac240ead (patch)
tree0a7237a7b29d8d05a2de5a971526b7021a7d4f4a /fail2ban/helpers.py
parent3fae8a7e432217c5ff650ef156a35663e4ccc78d (diff)
downloadfail2ban-a6318b159b0c2db5405aa525882e208aac240ead.tar.gz
substituteRecursiveTags optimization + moved in helpers facilities (because currently used commonly in server and in client)
Diffstat (limited to 'fail2ban/helpers.py')
-rw-r--r--fail2ban/helpers.py99
1 files changed, 99 insertions, 0 deletions
diff --git a/fail2ban/helpers.py b/fail2ban/helpers.py
index 4f4426b0..1e5a053b 100644
--- a/fail2ban/helpers.py
+++ b/fail2ban/helpers.py
@@ -200,6 +200,105 @@ else:
raise
return uni_decode(x, enc, 'replace')
+
+#
+# Following facilities used for safe recursive interpolation of
+# tags (<tag>) in tagged options.
+#
+
+# max tag replacement count:
+MAX_TAG_REPLACE_COUNT = 10
+
+# compiled RE for tag name (replacement name)
+TAG_CRE = re.compile(r'<([^ <>]+)>')
+
+def substituteRecursiveTags(inptags, conditional='',
+ ignore=(), addrepl=None
+):
+ """Sort out tag definitions within other tags.
+ Since v.0.9.2 supports embedded interpolation (see test cases for examples).
+
+ so: becomes:
+ a = 3 a = 3
+ b = <a>_3 b = 3_3
+
+ Parameters
+ ----------
+ inptags : dict
+ Dictionary of tags(keys) and their values.
+
+ Returns
+ -------
+ dict
+ Dictionary of tags(keys) and their values, with tags
+ within the values recursively replaced.
+ """
+ # copy return tags dict to prevent modifying of inptags:
+ tags = inptags.copy()
+ t = TAG_CRE
+ ignore = set(ignore)
+ done = set()
+ # repeat substitution while embedded-recursive (repFlag is True)
+ while True:
+ repFlag = False
+ # substitute each value:
+ for tag in tags.iterkeys():
+ # ignore escaped or already done (or in ignore list):
+ if tag in ignore or tag in done: continue
+ value = orgval = str(tags[tag])
+ # search and replace all tags within value, that can be interpolated using other tags:
+ m = t.search(value)
+ refCounts = {}
+ #logSys.log(5, 'TAG: %s, value: %s' % (tag, value))
+ while m:
+ found_tag = m.group(1)
+ # don't replace tags that should be currently ignored (pre-replacement):
+ if found_tag in ignore:
+ m = t.search(value, m.end())
+ continue
+ #logSys.log(5, 'found: %s' % found_tag)
+ if found_tag == tag or refCounts.get(found_tag, 1) > MAX_TAG_REPLACE_COUNT:
+ # recursive definitions are bad
+ #logSys.log(5, 'recursion fail tag: %s value: %s' % (tag, value) )
+ raise ValueError(
+ "properties contain self referencing definitions "
+ "and cannot be resolved, fail tag: %s, found: %s in %s, value: %s" %
+ (tag, found_tag, refCounts, value))
+ repl = None
+ if conditional:
+ repl = tags.get(found_tag + '?' + conditional)
+ if repl is None:
+ repl = tags.get(found_tag)
+ # try to find tag using additional replacement (callable):
+ if repl is None and addrepl is not None:
+ repl = addrepl(found_tag)
+ if repl is None:
+ # Missing tags - just continue on searching after end of match
+ # Missing tags are ok - cInfo can contain aInfo elements like <HOST> and valid shell
+ # constructs like <STDIN>.
+ m = t.search(value, m.end())
+ continue
+ value = value.replace('<%s>' % found_tag, repl)
+ #logSys.log(5, 'value now: %s' % value)
+ # increment reference count:
+ refCounts[found_tag] = refCounts.get(found_tag, 0) + 1
+ # the next match for replace:
+ m = t.search(value, m.start())
+ #logSys.log(5, 'TAG: %s, newvalue: %s' % (tag, value))
+ # was substituted?
+ if orgval != value:
+ # check still contains any tag - should be repeated (possible embedded-recursive substitution):
+ if t.search(value):
+ repFlag = True
+ tags[tag] = value
+ # no more sub tags (and no possible composite), add this tag to done set (just to be faster):
+ if '<' not in value: done.add(tag)
+ # stop interpolation, if no replacements anymore:
+ if not repFlag:
+ break
+ return tags
+
+
class BgService(object):
"""Background servicing