From b070dc89aa7b8b001aec26c293f968bf84f385b8 Mon Sep 17 00:00:00 2001 From: Cyril Jaquier Date: Sun, 13 Apr 2008 17:48:52 +0000 Subject: [PATCH] - Overwrote head with some of 0.8. git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@686 a942ae1a-1317-0410-a47c-b1dcaea8d605 --- CHANGELOG => ChangeLog | 0 MANIFEST | 27 +- README | 15 +- TODO | 12 - client/beautifier.py | 5 + client/configparserinc.py | 108 ++++++ client/configreader.py | 10 +- client/configurator.py | 8 +- client/csocket.py | 2 +- client/jailreader.py | 2 +- client/jailsreader.py | 22 +- common/protocol.py | 5 +- common/version.py | 2 +- config/action.d/dummy.conf | 8 +- config/action.d/hostsdeny.conf | 4 +- config/action.d/ipfw.conf | 2 +- config/action.d/iptables-allports.conf | 65 ++++ config/action.d/iptables-multiport-log.conf | 78 ++++ config/action.d/iptables-new.conf | 2 +- config/action.d/mail-buffered.conf | 16 +- config/action.d/mail-whois-lines.conf | 20 +- config/action.d/sendmail-buffered.conf | 105 +++++ config/action.d/sendmail-whois-lines.conf | 88 +++++ config/action.d/sendmail-whois.conf | 82 ++++ config/action.d/sendmail.conf | 80 ++++ config/fail2ban.conf | 4 +- config/filter.d/apache-badbots.conf | 4 +- config/filter.d/apache-noscript.conf | 2 +- config/filter.d/apache-overflows.conf | 20 + config/filter.d/common.conf | 41 ++ config/filter.d/gssftpd.conf | 14 + config/filter.d/named-refused.conf | 31 ++ config/filter.d/pam-generic.conf | 25 ++ config/filter.d/proftpd.conf | 5 +- config/filter.d/sshd.conf | 22 +- config/filter.d/vsftpd.conf | 4 +- config/filter.d/webmin-auth.conf | 28 ++ config/filter.d/xinetd-fail.conf | 30 ++ config/jail.conf | 62 ++- fail2ban-client | 46 ++- fail2ban-regex | 121 +++++- fail2ban-server | 15 +- files/cacti/README | 6 +- files/macosx-initd | 19 + files/redhat-initd | 4 +- files/suse-initd | 111 +++--- server/action.py | 11 +- server/{communication => }/asyncserver.py | 18 +- server/banmanager.py | 2 +- server/banticket.py | 50 --- server/communication/__init__.py | 25 -- server/datedetector.py | 90 ++--- server/dateepoch.py | 44 --- server/datestrptime.py | 85 ----- server/datetai64n.py | 46 --- server/datetemplate.py | 125 +++++- server/failmanager.py | 2 +- server/failregex.py | 74 +++- server/failticket.py | 37 -- server/filter.py | 400 ++++++++++---------- server/filtergamin.py | 21 +- server/filterpoll.py | 23 +- server/regex.py | 93 ----- server/server.py | 58 ++- server/ticket.py | 26 +- server/transmitter.py | 12 - setup.py | 10 +- testcases/actiontestcase.py | 2 +- testcases/banmanagertestcase.py | 12 +- testcases/datedetectortestcase.py | 24 +- testcases/failmanagertestcase.py | 5 +- testcases/filtertestcase.py | 16 +- 72 files changed, 1761 insertions(+), 932 deletions(-) rename CHANGELOG => ChangeLog (100%) create mode 100644 client/configparserinc.py create mode 100644 config/action.d/iptables-allports.conf create mode 100644 config/action.d/iptables-multiport-log.conf create mode 100644 config/action.d/sendmail-buffered.conf create mode 100644 config/action.d/sendmail-whois-lines.conf create mode 100644 config/action.d/sendmail-whois.conf create mode 100644 config/action.d/sendmail.conf create mode 100644 config/filter.d/apache-overflows.conf create mode 100644 config/filter.d/common.conf create mode 100644 config/filter.d/gssftpd.conf create mode 100644 config/filter.d/named-refused.conf create mode 100644 config/filter.d/pam-generic.conf create mode 100644 config/filter.d/webmin-auth.conf create mode 100644 config/filter.d/xinetd-fail.conf create mode 100644 files/macosx-initd rename server/{communication => }/asyncserver.py (91%) delete mode 100644 server/banticket.py delete mode 100644 server/communication/__init__.py delete mode 100644 server/dateepoch.py delete mode 100644 server/datestrptime.py delete mode 100644 server/datetai64n.py delete mode 100644 server/failticket.py delete mode 100644 server/regex.py diff --git a/CHANGELOG b/ChangeLog similarity index 100% rename from CHANGELOG rename to ChangeLog diff --git a/MANIFEST b/MANIFEST index 2176d8b2..877720af 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,5 +1,5 @@ README -CHANGELOG +ChangeLog TODO COPYING fail2ban-client @@ -7,6 +7,7 @@ fail2ban-server fail2ban-testcases fail2ban-regex client/configreader.py +client/configparserinc.py client/jailreader.py client/fail2banreader.py client/jailsreader.py @@ -16,15 +17,12 @@ client/actionreader.py client/__init__.py client/configurator.py client/csocket.py -server/banticket.py +server/asyncserver.py server/filter.py server/filtergamin.py server/filterpoll.py server/server.py -server/datestrptime.py -server/failticket.py server/actions.py -server/datetai64n.py server/faildata.py server/failmanager.py server/datedetector.py @@ -35,14 +33,10 @@ server/ticket.py server/jail.py server/jails.py server/__init__.py -server/dateepoch.py server/banmanager.py server/datetemplate.py server/mytime.py -server/regex.py server/failregex.py -server/communication/__init__.py -server/communication/asyncserver.py testcases/banmanagertestcase.py testcases/failmanagertestcase.py testcases/clientreadertestcase.py @@ -61,30 +55,43 @@ common/__init__.py common/version.py common/protocol.py config/jail.conf +config/filter.d/common.conf config/filter.d/apache-auth.conf config/filter.d/apache-badbots.conf config/filter.d/apache-noscript.conf +config/filter.d/apache-overflows.conf config/filter.d/courierlogin.conf config/filter.d/couriersmtp.conf config/filter.d/exim.conf +config/filter.d/gssftpd.conf +config/filter.d/named-refused.conf config/filter.d/postfix.conf config/filter.d/proftpd.conf config/filter.d/pure-ftpd.conf config/filter.d/qmail.conf +config/filter.d/pam-generic.conf config/filter.d/sasl.conf config/filter.d/sshd.conf config/filter.d/sshd-ddos.conf config/filter.d/vsftpd.conf +config/filter.d/webmin-auth.conf config/filter.d/wuftpd.conf +config/filter.d/xinetd-fail.conf config/action.d/hostsdeny.conf config/action.d/ipfw.conf config/action.d/iptables.conf +config/action.d/iptables-allports.conf config/action.d/iptables-multiport.conf +config/action.d/iptables-multiport-log.conf config/action.d/iptables-new.conf config/action.d/mail.conf config/action.d/mail-buffered.conf config/action.d/mail-whois.conf config/action.d/mail-whois-lines.conf +config/action.d/sendmail.conf +config/action.d/sendmail-buffered.conf +config/action.d/sendmail-whois.conf +config/action.d/sendmail-whois-lines.conf config/action.d/shorewall.conf config/fail2ban.conf man/fail2ban-client.1 @@ -97,8 +104,10 @@ man/generate-man files/gentoo-initd files/gentoo-confd files/redhat-initd +files/macosx-initd files/solaris-fail2ban.xml files/solaris-svc-fail2ban +files/suse-initd files/cacti/fail2ban_stats.sh files/cacti/cacti_host_template_fail2ban.xml files/cacti/README diff --git a/README b/README index 7a4aa86f..7d2a4281 100644 --- a/README +++ b/README @@ -4,7 +4,7 @@ |_| \__,_|_|_/___|_.__/\__,_|_||_| ============================================================= -Fail2Ban (version 0.8.0) 2007/05/03 +Fail2Ban (version 0.8.3) 2008/??/?? ============================================================= Fail2Ban scans log files like /var/log/pwdfail and bans IP @@ -21,15 +21,15 @@ Installation: ------------- Required: - >=python-2.4 (http://www.python.org) + >=python-2.3 (http://www.python.org) Optional: >=gamin-0.0.21 (http://www.gnome.org/~veillard/gamin) To install, just do: -> tar xvfj fail2ban-0.8.0.tar.bz2 -> cd fail2ban-0.8.0 +> tar xvfj fail2ban-0.8.3.tar.bz2 +> cd fail2ban-0.8.3 > python setup.py install This will install Fail2Ban into /usr/share/fail2ban. The @@ -62,7 +62,7 @@ appreciate this program, you can contact me at: Website: http://www.fail2ban.org -Cyril Jaquier: +Cyril Jaquier: Thanks: ------- @@ -73,7 +73,10 @@ Jonathan Kamens, Stephen Gildea, Markus Hoffmann, Mark Edgington, Patrick Börjesson, kojiro, zugeschmiert, Tyler, Nick Munger, Christoph Haas, Justin Shore, Joël Bertrand, René Berber, mEDI, Axel Thimm, Eric Gerbier, Christian Rauch, -Michael C. Haller, Jonathan Underwood, Hanno 'Rince' Wagner +Michael C. Haller, Jonathan Underwood, Hanno 'Rince' Wagner, +Daniel B. Cid, David Nutter, Raphaël Marichez, Guillaume +Delvit, Vaclav Misek, Adrien Clerc, Michael Hanselmann, +Vincent Deffontaines, Bill Heaton and many others. License: -------- diff --git a/TODO b/TODO index 77006f70..318f839e 100644 --- a/TODO +++ b/TODO @@ -13,16 +13,8 @@ Legend: # partially done * done -- should not be mandatory. It should be possible to - start an action without an host - -- Use Python 2.3 - - Removed relative imports -- Discuss where Fail2ban should be installed (/usr/share, - /usr/lib/python/site-packages/, etc) - - Cleanup fail2ban-client and fail2ban-server. Move code to server/ and client/ @@ -50,12 +42,8 @@ Legend: - Add gettext support (I18N) -- Fix the cPickle issue with Python 2.5 - - Multiline log reading -- Improve communication. (asyncore, asynchat??) - - Improve execution of action. Why does subprocess.call deadlock with multi-jails? diff --git a/client/beautifier.py b/client/beautifier.py index 132d1626..ab98b294 100644 --- a/client/beautifier.py +++ b/client/beautifier.py @@ -72,9 +72,14 @@ class Beautifier: ipList = "" for ip in response[1][1][2][1]: ipList += ip + " " + # Creates file list. + fileList = "" + for f in response[0][1][2][1]: + fileList += f + " " # Display information msg = "Status for the jail: " + inC[1] + "\n" msg = msg + "|- " + response[0][0] + "\n" + msg = msg + "| |- " + response[0][1][2][0] + ":\t" + fileList + "\n" msg = msg + "| |- " + response[0][1][0][0] + ":\t" + `response[0][1][0][1]` + "\n" msg = msg + "| `- " + response[0][1][1][0] + ":\t" + `response[0][1][1][1]` + "\n" msg = msg + "`- " + response[1][0] + "\n" diff --git a/client/configparserinc.py b/client/configparserinc.py new file mode 100644 index 00000000..59253c13 --- /dev/null +++ b/client/configparserinc.py @@ -0,0 +1,108 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Yaroslav Halchenko +# Modified: Cyril Jaquier +# $Revision: 656 $ + +__author__ = 'Yaroslav Halhenko' +__revision__ = '$Revision: $' +__date__ = '$Date: $' +__copyright__ = 'Copyright (c) 2007 Yaroslav Halchenko' +__license__ = 'GPL' + +import logging, os +from ConfigParser import SafeConfigParser + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.client.config") + +class SafeConfigParserWithIncludes(SafeConfigParser): + """ + Class adds functionality to SafeConfigParser to handle included + other configuration files (or may be urls, whatever in the future) + + File should have section [includes] and only 2 options implemented + are 'files_before' and 'files_after' where files are listed 1 per + line. + + Example: + +[INCLUDES] +before = 1.conf + 3.conf + +after = 1.conf + + It is a simple implementation, so just basic care is taken about + recursion. Includes preserve right order, ie new files are + inserted to the list of read configs before original, and their + includes correspondingly so the list should follow the leaves of + the tree. + + I wasn't sure what would be the right way to implement generic (aka c++ + template) so we could base at any *configparser class... so I will + leave it for the future + + """ + + SECTION_NAME = "INCLUDES" + + #@staticmethod + def getIncludes(resource, seen = []): + """ + Given 1 config resource returns list of included files + (recursively) with the original one as well + Simple loops are taken care about + """ + + # Use a short class name ;) + SCPWI = SafeConfigParserWithIncludes + + parser = SafeConfigParser() + parser.read(resource) + + resourceDir = os.path.dirname(resource) + + newFiles = [ ('before', []), ('after', []) ] + if SCPWI.SECTION_NAME in parser.sections(): + for option_name, option_list in newFiles: + if option_name in parser.options(SCPWI.SECTION_NAME): + newResources = parser.get(SCPWI.SECTION_NAME, option_name) + for newResource in newResources.split('\n'): + if os.path.isabs(newResource): + r = newResource + else: + r = "%s/%s" % (resourceDir, newResource) + if r in seen: + continue + s = seen + [resource] + option_list += SCPWI.getIncludes(r, s) + # combine lists + return newFiles[0][1] + [resource] + newFiles[1][1] + #print "Includes list for " + resource + " is " + `resources` + getIncludes = staticmethod(getIncludes) + + + def read(self, filenames): + fileNamesFull = [] + if not isinstance(filenames, list): + filenames = [ filenames ] + for filename in filenames: + fileNamesFull += SafeConfigParserWithIncludes.getIncludes(filename) + logSys.debug("Reading files: %s" % fileNamesFull) + return SafeConfigParser.read(self, fileNamesFull) + diff --git a/client/configreader.py b/client/configreader.py index 46b3c5dd..f8e9ade8 100644 --- a/client/configreader.py +++ b/client/configreader.py @@ -15,7 +15,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Author: Cyril Jaquier -# +# Modified by: Yaroslav Halchenko (SafeConfigParserWithIncludes) # $Revision$ __author__ = "Cyril Jaquier" @@ -25,18 +25,18 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" import logging, os -from ConfigParser import SafeConfigParser +from configparserinc import SafeConfigParserWithIncludes from ConfigParser import NoOptionError, NoSectionError # Gets the instance of the logger. logSys = logging.getLogger("fail2ban.client.config") -class ConfigReader(SafeConfigParser): +class ConfigReader(SafeConfigParserWithIncludes): BASE_DIRECTORY = "/etc/fail2ban/" def __init__(self): - SafeConfigParser.__init__(self) + SafeConfigParserWithIncludes.__init__(self) self.__opts = None #@staticmethod @@ -56,7 +56,7 @@ class ConfigReader(SafeConfigParser): bConf = basename + ".conf" bLocal = basename + ".local" if os.path.exists(bConf) or os.path.exists(bLocal): - SafeConfigParser.read(self, [bConf, bLocal]) + SafeConfigParserWithIncludes.read(self, [bConf, bLocal]) return True else: logSys.error(bConf + " and " + bLocal + " do not exist") diff --git a/client/configurator.py b/client/configurator.py index 80ff968f..8c3a69dd 100644 --- a/client/configurator.py +++ b/client/configurator.py @@ -56,13 +56,13 @@ class Configurator: def readAll(self): self.readEarly() self.__jails.read() - + def getEarlyOptions(self): return self.__fail2ban.getEarlyOptions() - - def getAllOptions(self): + + def getOptions(self, jail = None): self.__fail2ban.getOptions() - return self.__jails.getOptions() + return self.__jails.getOptions(jail) def convertToProtocol(self): self.__streams["general"] = self.__fail2ban.convert() diff --git a/client/csocket.py b/client/csocket.py index 56f6fc20..13bae5f8 100644 --- a/client/csocket.py +++ b/client/csocket.py @@ -32,7 +32,7 @@ class CSocket: END_STRING = "" - def __init__(self, sock = "/tmp/fail2ban.sock"): + def __init__(self, sock = "/var/run/fail2ban/fail2ban.sock"): # Create an INET, STREAMing socket #self.csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.__csock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) diff --git a/client/jailreader.py b/client/jailreader.py index 58e87381..5ba44034 100644 --- a/client/jailreader.py +++ b/client/jailreader.py @@ -90,7 +90,7 @@ class JailReader(ConfigReader): self.__actions.append(action) else: raise AttributeError("Unable to read action") - except AttributeError, e: + except Exception, e: logSys.error("Error in action definition " + act) logSys.debug(e) return False diff --git a/client/jailsreader.py b/client/jailsreader.py index ada5fe09..620e7b45 100644 --- a/client/jailsreader.py +++ b/client/jailsreader.py @@ -40,12 +40,13 @@ class JailsReader(ConfigReader): def read(self): ConfigReader.read(self, "jail") - def getOptions(self): + def getOptions(self, section = None): opts = [] self.__opts = ConfigReader.getOptions(self, "Definition", opts) - for sec in self.sections(): - jail = JailReader(sec) + if section: + # Get the options of a specific jail. + jail = JailReader(section) jail.read() ret = jail.getOptions() if ret: @@ -53,8 +54,21 @@ class JailsReader(ConfigReader): # We only add enabled jails self.__jails.append(jail) else: - logSys.error("Errors in jail '" + sec + "'. Skipping...") + logSys.error("Errors in jail '%s'. Skipping..." % section) return False + else: + # Get the options of all jails. + for sec in self.sections(): + jail = JailReader(sec) + jail.read() + ret = jail.getOptions() + if ret: + if jail.isEnabled(): + # We only add enabled jails + self.__jails.append(jail) + else: + logSys.error("Errors in jail '" + sec + "'. Skipping...") + return False return True def convert(self): diff --git a/common/protocol.py b/common/protocol.py index 85d4947b..fa9f8b54 100644 --- a/common/protocol.py +++ b/common/protocol.py @@ -33,6 +33,7 @@ protocol = [ ['', "BASIC", ""], ["start", "starts the server and the jails"], ["reload", "reloads the configuration"], +["reload ", "reloads the jail "], ["stop", "stops all jails and terminate the server"], ["status", "gets the current status of the server"], ["ping", "tests if the server is alive"], @@ -51,9 +52,7 @@ protocol = [ ["set addignoreip ", "adds to the ignore list of "], ["set delignoreip ", "removes from the ignore list of "], ["set addlogpath ", "adds to the monitoring list of "], -["set dellogpath ", "removes to the monitoring list of "], -["set timeregex ", "sets the regular expression to match the date format for . This will disable the autodetection feature."], -["set timepattern ", "sets the pattern to match the date format for . This will disable the autodetection feature."], +["set dellogpath ", "removes to the monitoring list of "], ["set addfailregex ", "adds the regular expression which must match failures for "], ["set delfailregex ", "removes the regular expression at for failregex"], ["set addignoreregex ", "adds the regular expression which should match pattern to exclude for "], diff --git a/common/version.py b/common/version.py index d83cd774..79c66b15 100644 --- a/common/version.py +++ b/common/version.py @@ -24,4 +24,4 @@ __date__ = "$Date$" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -version = "0.9.0-SVN" +version = "0.8.2-SVN" diff --git a/config/action.d/dummy.conf b/config/action.d/dummy.conf index cc729fdd..12ceefed 100644 --- a/config/action.d/dummy.conf +++ b/config/action.d/dummy.conf @@ -12,9 +12,9 @@ # Values: CMD # actionstart = touch /tmp/fail2ban.dummy - echo "" >> /tmp/fail2ban.dummy + printf %%b "\n" >> /tmp/fail2ban.dummy -# Option: actionend +# Option: actionstop # Notes.: command executed once at the end of Fail2Ban # Values: CMD # @@ -34,7 +34,7 @@ actioncheck = #