action.py

Go to the documentation of this file.
00001 # This file is part of Fail2Ban.
00002 #
00003 # Fail2Ban is free software; you can redistribute it and/or modify
00004 # it under the terms of the GNU General Public License as published by
00005 # the Free Software Foundation; either version 2 of the License, or
00006 # (at your option) any later version.
00007 #
00008 # Fail2Ban is distributed in the hope that it will be useful,
00009 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 # GNU General Public License for more details.
00012 #
00013 # You should have received a copy of the GNU General Public License
00014 # along with Fail2Ban; if not, write to the Free Software
00015 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00016 
00017 # Author: Cyril Jaquier
00018 # 
00019 # $Revision: 686 $
00020 
00021 __author__ = "Cyril Jaquier"
00022 __version__ = "$Revision: 686 $"
00023 __date__ = "$Date: 2008-04-13 19:48:52 +0200 (Sun, 13 Apr 2008) $"
00024 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
00025 __license__ = "GPL"
00026 
00027 import logging, os
00028 #from subprocess import call
00029 
00030 # Gets the instance of the logger.
00031 logSys = logging.getLogger("fail2ban.actions.action")
00032 
00033 ##
00034 # Execute commands.
00035 #
00036 # This class reads the failures from the Jail queue and decide if an
00037 # action has to be taken. A BanManager take care of the banned IP
00038 # addresses.
00039 
00040 class Action:
00041     
00042     def __init__(self, name):
00043         self.__name = name
00044         self.__cInfo = dict()
00045         ## Command executed in order to initialize the system.
00046         self.__actionStart = ''
00047         ## Command executed when an IP address gets banned.
00048         self.__actionBan = ''
00049         ## Command executed when an IP address gets removed.
00050         self.__actionUnban = ''
00051         ## Command executed in order to check requirements.
00052         self.__actionCheck = ''
00053         ## Command executed in order to stop the system.
00054         self.__actionStop = ''
00055         logSys.debug("Created Action")
00056     
00057     ##
00058     # Sets the action name.
00059     #
00060     # @param name the name of the action
00061     
00062     def setName(self, name):
00063         self.__name = name
00064     
00065     ##
00066     # Returns the action name.
00067     #
00068     # @return the name of the action
00069     
00070     def getName(self):
00071         return self.__name
00072     
00073     ##
00074     # Sets a "CInfo".
00075     #
00076     # CInfo are statically defined properties. They can be definied by
00077     # the user and are used to set e-mail addresses, port, host or
00078     # anything that should not change during the life of the server.
00079     #
00080     # @param key the property name
00081     # @param value the property value
00082     
00083     def setCInfo(self, key, value):
00084         self.__cInfo[key] = value
00085     
00086     ##
00087     # Returns a "CInfo".
00088     #
00089     # @param key the property name
00090     
00091     def getCInfo(self, key):
00092         return self.__cInfo[key]
00093     
00094     ##
00095     # Removes a "CInfo".
00096     #
00097     # @param key the property name
00098     
00099     def delCInfo(self, key):
00100         del self.__cInfo[key]
00101     
00102     ##
00103     # Set the "start" command.
00104     #
00105     # @param value the command
00106         
00107     def setActionStart(self, value):
00108         self.__actionStart = value
00109         logSys.debug("Set actionStart = %s" % value)
00110     
00111     ##
00112     # Get the "start" command.
00113     #
00114     # @return the command
00115     
00116     def getActionStart(self):
00117         return self.__actionStart
00118     
00119     ##
00120     # Executes the action "start" command.
00121     #
00122     # Replaces the tags in the action command with value of "cInfo"
00123     # and executes the resulting command.
00124     #
00125     # @return True if the command succeeded
00126     
00127     def execActionStart(self):
00128         startCmd = Action.replaceTag(self.__actionStart, self.__cInfo)
00129         return Action.executeCmd(startCmd)
00130     
00131     ##
00132     # Set the "ban" command.
00133     #
00134     # @param value the command
00135     
00136     def setActionBan(self, value):
00137         self.__actionBan = value
00138         logSys.debug("Set actionBan = %s" % value)
00139     
00140     ##
00141     # Get the "ban" command.
00142     #
00143     # @return the command
00144     
00145     def getActionBan(self):
00146         return self.__actionBan
00147     
00148     ##
00149     # Executes the action "ban" command.
00150     #
00151     # @return True if the command succeeded
00152     
00153     def execActionBan(self, aInfo):
00154         return self.__processCmd(self.__actionBan, aInfo)
00155     
00156     ##
00157     # Set the "unban" command.
00158     #
00159     # @param value the command
00160     
00161     def setActionUnban(self, value):
00162         self.__actionUnban = value
00163         logSys.debug("Set actionUnban = %s" % value)
00164     
00165     ##
00166     # Get the "unban" command.
00167     #
00168     # @return the command
00169     
00170     def getActionUnban(self):
00171         return self.__actionUnban
00172     
00173     ##
00174     # Executes the action "unban" command.
00175     #
00176     # @return True if the command succeeded
00177     
00178     def execActionUnban(self, aInfo):
00179         return self.__processCmd(self.__actionUnban, aInfo)
00180     
00181     ##
00182     # Set the "check" command.
00183     #
00184     # @param value the command
00185     
00186     def setActionCheck(self, value):
00187         self.__actionCheck = value
00188         logSys.debug("Set actionCheck = %s" % value)
00189     
00190     ##
00191     # Get the "check" command.
00192     #
00193     # @return the command
00194     
00195     def getActionCheck(self):
00196         return self.__actionCheck
00197     
00198     ##
00199     # Set the "stop" command.
00200     #
00201     # @param value the command
00202     
00203     def setActionStop(self, value):
00204         self.__actionStop = value
00205         logSys.debug("Set actionStop = %s" % value)
00206     
00207     ##
00208     # Get the "stop" command.
00209     #
00210     # @return the command
00211     
00212     def getActionStop(self):
00213         return self.__actionStop
00214     
00215     ##
00216     # Executes the action "stop" command.
00217     #
00218     # Replaces the tags in the action command with value of "cInfo"
00219     # and executes the resulting command.
00220     #
00221     # @return True if the command succeeded
00222     
00223     def execActionStop(self):
00224         stopCmd = Action.replaceTag(self.__actionStop, self.__cInfo)
00225         return Action.executeCmd(stopCmd)
00226     
00227     ##
00228     # Replaces tags in query with property values in aInfo.
00229     #
00230     # @param query the query string with tags
00231     # @param aInfo the properties
00232     # @return a string
00233     
00234     #@staticmethod
00235     def replaceTag(query, aInfo):
00236         """ Replace tags in query
00237         """
00238         string = query
00239         for tag in aInfo:
00240             string = string.replace('<' + tag + '>', str(aInfo[tag]))
00241         # New line
00242         string = string.replace("<br>", '\n')
00243         return string
00244     replaceTag = staticmethod(replaceTag)
00245     
00246     ##
00247     # Executes a command with preliminary checks and substitutions.
00248     #
00249     # Before executing any commands, executes the "check" command first
00250     # in order to check if prerequirements are met. If this check fails,
00251     # it tries to restore a sane environnement before executing the real
00252     # command.
00253     # Replaces "aInfo" and "cInfo" in the query too.
00254     #
00255     # @param cmd The command to execute
00256     # @param aInfo Dynamic properties
00257     # @return True if the command succeeded
00258     
00259     def __processCmd(self, cmd, aInfo = None):
00260         """ Executes an OS command.
00261         """
00262         if cmd == "":
00263             logSys.debug("Nothing to do")
00264             return True
00265         
00266         checkCmd = Action.replaceTag(self.__actionCheck, self.__cInfo)
00267         if not Action.executeCmd(checkCmd):
00268             logSys.error("Invariant check failed. Trying to restore a sane" +
00269                          " environment")
00270             stopCmd = Action.replaceTag(self.__actionStop, self.__cInfo)
00271             Action.executeCmd(stopCmd)
00272             startCmd = Action.replaceTag(self.__actionStart, self.__cInfo)
00273             Action.executeCmd(startCmd)
00274             if not Action.executeCmd(checkCmd):
00275                 logSys.fatal("Unable to restore environment")
00276                 return False
00277 
00278         # Replace tags
00279         if not aInfo == None:
00280             realCmd = Action.replaceTag(cmd, aInfo)
00281         else:
00282             realCmd = cmd
00283         
00284         # Replace static fields
00285         realCmd = Action.replaceTag(realCmd, self.__cInfo)
00286         
00287         return Action.executeCmd(realCmd)
00288 
00289     ##
00290     # Executes a command.
00291     #
00292     # We need a shell here because commands are mainly shell script. They
00293     # contain pipe, redirection, etc.
00294     # 
00295     # @todo Force the use of bash!?
00296     # @todo Kill the command after a given timeout
00297     #
00298     # @param realCmd the command to execute
00299     # @return True if the command succeeded
00300 
00301     #@staticmethod
00302     def executeCmd(realCmd):
00303         logSys.debug(realCmd)
00304         try:
00305             # The following line gives deadlock with multiple jails
00306             #retcode = call(realCmd, shell=True)
00307             retcode = os.system(realCmd)
00308             if retcode == 0:
00309                 logSys.debug("%s returned successfully" % realCmd)
00310                 return True
00311             else:
00312                 logSys.error("%s returned %x" % (realCmd, retcode))
00313         except OSError, e:
00314             logSys.error("%s failed with %s" % (realCmd, e))
00315         return False
00316     executeCmd = staticmethod(executeCmd)
00317     
Generated on Thu Jun 20 03:01:40 2013 for Fail2Ban by  doxygen 1.6.3