"Fossies" - the Fresh Open Source Software Archive

Member "fail2ban-0.11.1/fail2ban/client/jailreader.py" (11 Jan 2020, 8980 Bytes) of package /linux/misc/fail2ban-0.11.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "jailreader.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.10.5_vs_0.11.1.

    1 # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
    2 # vi: set ft=python sts=4 ts=4 sw=4 noet :
    3 
    4 # This file is part of Fail2Ban.
    5 #
    6 # Fail2Ban is free software; you can redistribute it and/or modify
    7 # it under the terms of the GNU General Public License as published by
    8 # the Free Software Foundation; either version 2 of the License, or
    9 # (at your option) any later version.
   10 #
   11 # Fail2Ban is distributed in the hope that it will be useful,
   12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 # GNU General Public License for more details.
   15 #
   16 # You should have received a copy of the GNU General Public License
   17 # along with Fail2Ban; if not, write to the Free Software
   18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   19 
   20 # Author: Cyril Jaquier
   21 # 
   22 
   23 __author__ = "Cyril Jaquier"
   24 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
   25 __license__ = "GPL"
   26 
   27 import glob
   28 import json
   29 import os.path
   30 import re
   31 
   32 from .configreader import ConfigReaderUnshared, ConfigReader
   33 from .filterreader import FilterReader
   34 from .actionreader import ActionReader
   35 from ..version import version
   36 from ..helpers import getLogger, extractOptions, splitWithOptions, splitwords
   37 
   38 # Gets the instance of the logger.
   39 logSys = getLogger(__name__)
   40 
   41 
   42 class JailReader(ConfigReader):
   43     
   44     def __init__(self, name, force_enable=False, **kwargs):
   45         ConfigReader.__init__(self, **kwargs)
   46         self.__name = name
   47         self.__filter = None
   48         self.__force_enable = force_enable
   49         self.__actions = list()
   50         self.__opts = None
   51     
   52     @property
   53     def options(self):
   54         return self.__opts
   55 
   56     def setName(self, value):
   57         self.__name = value
   58     
   59     def getName(self):
   60         return self.__name
   61     
   62     def read(self):
   63         out = ConfigReader.read(self, "jail")
   64         # Before returning -- verify that requested section
   65         # exists at all
   66         if not (self.__name in self.sections()):
   67             raise ValueError("Jail %r was not found among available"
   68                              % self.__name)
   69         return out
   70     
   71     def isEnabled(self):
   72         return self.__force_enable or (
   73             self.__opts and self.__opts.get("enabled", False))
   74 
   75     @staticmethod
   76     def _glob(path):
   77         """Given a path for glob return list of files to be passed to server.
   78 
   79         Dangling symlinks are warned about and not returned
   80         """
   81         pathList = []
   82         for p in glob.glob(path):
   83             if os.path.exists(p):
   84                 pathList.append(p)
   85             else:
   86                 logSys.warning("File %s is a dangling link, thus cannot be monitored" % p)
   87         return pathList
   88 
   89     _configOpts1st = {
   90         "enabled": ["bool", False],
   91         "backend": ["string", "auto"],
   92         "filter": ["string", ""]
   93     }
   94     _configOpts = {
   95         "enabled": ["bool", False],
   96         "backend": ["string", "auto"],
   97         "maxretry": ["int", None],
   98         "maxmatches": ["int", None],
   99         "findtime": ["string", None],
  100         "bantime": ["string", None],
  101         "bantime.increment": ["bool", None],
  102         "bantime.factor": ["string", None],
  103         "bantime.formula": ["string", None],
  104         "bantime.multipliers": ["string", None],
  105         "bantime.maxtime": ["string", None],
  106         "bantime.rndtime": ["string", None],
  107         "bantime.overalljails": ["bool", None],
  108         "ignorecommand": ["string", None],
  109         "ignoreself": ["bool", None],
  110         "ignoreip": ["string", None],
  111         "ignorecache": ["string", None],
  112         "filter": ["string", ""],
  113         "logtimezone": ["string", None],
  114         "logencoding": ["string", None],
  115         "logpath": ["string", None],
  116         "action": ["string", ""]
  117     }
  118     _configOpts.update(FilterReader._configOpts)
  119 
  120     _ignoreOpts = set(['action', 'filter', 'enabled'] + FilterReader._configOpts.keys())
  121 
  122     def getOptions(self):
  123 
  124         # Before interpolation (substitution) add static options always available as default:
  125         self.merge_defaults({
  126             "fail2ban_version": version
  127         })
  128 
  129         try:
  130 
  131             # Read first options only needed for merge defaults ('known/...' from filter):
  132             self.__opts = ConfigReader.getOptions(self, self.__name, self._configOpts1st,
  133                 shouldExist=True)
  134             if not self.__opts: # pragma: no cover
  135                 raise JailDefError("Init jail options failed")
  136         
  137             if not self.isEnabled():
  138                 return True
  139                 
  140             # Read filter
  141             flt = self.__opts["filter"]
  142             if flt:
  143                 filterName, filterOpt = extractOptions(flt)
  144                 if not filterName:
  145                     raise JailDefError("Invalid filter definition %r" % flt)
  146                 self.__filter = FilterReader(
  147                     filterName, self.__name, filterOpt, 
  148                     share_config=self.share_config, basedir=self.getBaseDir())
  149                 ret = self.__filter.read()
  150                 if not ret:
  151                     raise JailDefError("Unable to read the filter %r" % filterName)
  152                 if not filterOpt.get('logtype'):
  153                     # overwrite default logtype backend-related (considering that the filter settings may be overwritten):
  154                     self.__filter.merge_defaults({
  155                         'logtype': ['file','journal'][int(self.__opts.get('backend', '').startswith("systemd"))]
  156                     })
  157                 # merge options from filter as 'known/...' (all options unfiltered):
  158                 self.__filter.getOptions(self.__opts, all=True)
  159                 ConfigReader.merge_section(self, self.__name, self.__filter.getCombined(), 'known/')
  160             else:
  161                 self.__filter = None
  162                 logSys.warning("No filter set for jail %s" % self.__name)
  163 
  164             # Read second all options (so variables like %(known/param) can be interpolated):
  165             self.__opts = ConfigReader.getOptions(self, self.__name, self._configOpts)
  166             if not self.__opts: # pragma: no cover
  167                 raise JailDefError("Read jail options failed")
  168         
  169             # cumulate filter options again (ignore given in jail):
  170             if self.__filter:
  171                 self.__filter.getOptions(self.__opts)
  172         
  173             # Read action
  174             for act in splitWithOptions(self.__opts["action"]):
  175                 try:
  176                     act = act.strip()
  177                     if not act:           # skip empty actions
  178                         continue
  179                     # join with previous line if needed (consider possible new-line):
  180                     actName, actOpt = extractOptions(act)
  181                     prevln = ''
  182                     if not actName:
  183                         raise JailDefError("Invalid action definition %r" % act)
  184                     if actName.endswith(".py"):
  185                         self.__actions.append([
  186                             "set",
  187                             self.__name,
  188                             "addaction",
  189                             actOpt.pop("actname", os.path.splitext(actName)[0]),
  190                             os.path.join(
  191                                 self.getBaseDir(), "action.d", actName),
  192                             json.dumps(actOpt),
  193                             ])
  194                     else:
  195                         action = ActionReader(
  196                             actName, self.__name, actOpt,
  197                             share_config=self.share_config, basedir=self.getBaseDir())
  198                         ret = action.read()
  199                         if ret:
  200                             action.getOptions(self.__opts)
  201                             self.__actions.append(action)
  202                         else:
  203                             raise JailDefError("Unable to read action %r" % actName)
  204                 except JailDefError:
  205                     raise
  206                 except Exception as e:
  207                     logSys.debug("Caught exception: %s", e, exc_info=True)
  208                     raise ValueError("Error in action definition %r: %r" % (act, e))
  209             if not len(self.__actions):
  210                 logSys.warning("No actions were defined for %s" % self.__name)
  211             
  212         except JailDefError as e:
  213             e = str(e)
  214             logSys.error(e)
  215             if not self.__opts:
  216                 self.__opts = dict()
  217             self.__opts['config-error'] = e
  218             return False
  219         return True
  220     
  221     def convert(self, allow_no_files=False):
  222         """Convert read before __opts to the commands stream
  223 
  224         Parameters
  225         ----------
  226         allow_missing : bool
  227           Either to allow log files to be missing entirely.  Primarily is
  228           used for testing
  229          """
  230 
  231         stream = []
  232         stream2 = []
  233         e = self.__opts.get('config-error')
  234         if e:
  235             stream.extend([['config-error', "Jail '%s' skipped, because of wrong configuration: %s" % (self.__name, e)]])
  236             return stream
  237         # fill jail with filter options, using filter (only not overriden in jail):
  238         if self.__filter:
  239             stream.extend(self.__filter.convert())
  240         # and using options from jail:
  241         FilterReader._fillStream(stream, self.__opts, self.__name)
  242         for opt, value in self.__opts.iteritems():
  243             if opt == "logpath":
  244                 if self.__opts.get('backend', '').startswith("systemd"): continue
  245                 found_files = 0
  246                 for path in value.split("\n"):
  247                     path = path.rsplit(" ", 1)
  248                     path, tail = path if len(path) > 1 else (path[0], "head")
  249                     pathList = JailReader._glob(path)
  250                     if len(pathList) == 0:
  251                         logSys.notice("No file(s) found for glob %s" % path)
  252                     for p in pathList:
  253                         found_files += 1
  254                         # logpath after all log-related data (backend, date-pattern, etc)
  255                         stream2.append(
  256                             ["set", self.__name, "addlogpath", p, tail])
  257                 if not found_files:
  258                     msg = "Have not found any log file for %s jail" % self.__name
  259                     if not allow_no_files:
  260                         raise ValueError(msg)
  261                     logSys.warning(msg)
  262             elif opt == "backend":
  263                 backend = value
  264             elif opt == "ignoreip":
  265                 stream.append(["set", self.__name, "addignoreip"] + splitwords(value))
  266             elif opt not in JailReader._ignoreOpts:
  267                 stream.append(["set", self.__name, opt, value])
  268         # consider options order (after other options):
  269         if stream2: stream += stream2
  270         for action in self.__actions:
  271             if isinstance(action, (ConfigReaderUnshared, ConfigReader)):
  272                 stream.extend(action.convert())
  273             else:
  274                 stream.append(action)
  275         stream.insert(0, ["add", self.__name, backend])
  276         return stream
  277     
  278 class JailDefError(Exception):
  279     pass