~ubuntu-branches/ubuntu/wily/fail2ban/wily-proposed

« back to all changes in this revision

Viewing changes to fail2ban/server/action.py

  • Committer: Package Import Robot
  • Author(s): Yaroslav Halchenko
  • Date: 2015-07-31 21:34:10 UTC
  • mfrom: (1.2.13)
  • Revision ID: package-import@ubuntu.com-20150731213410-928fao1ss71tv5zt
Tags: 0.9.3-1
* Fresh upstream release
* debian/control -- adjusted description to mention what Recommends
  and Suggests are good for (Closes: #767114)

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2012 Yaroslav Halchenko"
22
22
__license__ = "GPL"
23
23
 
24
 
import logging, os, subprocess, time, signal, tempfile
25
 
import threading, re
 
24
import logging
 
25
import os
 
26
import re
 
27
import signal
 
28
import subprocess
 
29
import tempfile
 
30
import threading
 
31
import time
26
32
from abc import ABCMeta
27
33
from collections import MutableMapping
28
34
 
49
55
signame = dict((num, name)
50
56
        for name, num in signal.__dict__.iteritems() if name.startswith("SIG"))
51
57
 
 
58
 
52
59
class CallingMap(MutableMapping):
53
60
        """A Mapping type which returns the result of callable values.
54
61
 
94
101
        def copy(self):
95
102
                return self.__class__(self.data.copy())
96
103
 
 
104
 
97
105
class ActionBase(object):
98
106
        """An abstract base class for actions in Fail2Ban.
99
107
 
176
184
                """
177
185
                pass
178
186
 
 
187
 
179
188
class CommandAction(ActionBase):
180
189
        """A action which executes OS shell commands.
181
190
 
400
409
                                                # recursive definitions are bad
401
410
                                                #logSys.log(5, 'recursion fail tag: %s value: %s' % (tag, value) )
402
411
                                                return False
403
 
                                        if found_tag in cls._escapedTags or not tags.has_key(found_tag):
 
412
                                        if found_tag in cls._escapedTags or not found_tag in tags:
404
413
                                                # Escaped or missing tags - just continue on searching after end of match
405
414
                                                # Missing tags are ok - cInfo can contain aInfo elements like <HOST> and valid shell
406
415
                                                # constructs like <STDIN>.
516
525
                        realCmd = self.replaceTag(cmd, aInfo)
517
526
                else:
518
527
                        realCmd = cmd
519
 
                
 
528
 
520
529
                # Replace static fields
521
530
                realCmd = self.replaceTag(realCmd, self._properties)
522
 
                
 
531
 
523
532
                return self.executeCmd(realCmd, self.timeout)
524
533
 
525
534
        @staticmethod
549
558
                if not realCmd:
550
559
                        logSys.debug("Nothing to do")
551
560
                        return True
552
 
                
 
561
 
553
562
                _cmd_lock.acquire()
554
563
                try: # Try wrapped within another try needed for python version < 2.5
555
564
                        stdout = tempfile.TemporaryFile(suffix=".stdout", prefix="fai2ban_")
556
565
                        stderr = tempfile.TemporaryFile(suffix=".stderr", prefix="fai2ban_")
557
566
                        try:
558
567
                                popen = subprocess.Popen(
559
 
                                        realCmd, stdout=stdout, stderr=stderr, shell=True)
 
568
                                        realCmd, stdout=stdout, stderr=stderr, shell=True,
 
569
                                        preexec_fn=os.setsid  # so that killpg does not kill our process
 
570
                                )
560
571
                                stime = time.time()
561
572
                                retcode = popen.poll()
562
573
                                while time.time() - stime <= timeout and retcode is None:
565
576
                                if retcode is None:
566
577
                                        logSys.error("%s -- timed out after %i seconds." %
567
578
                                                (realCmd, timeout))
568
 
                                        os.kill(popen.pid, signal.SIGTERM) # Terminate the process
 
579
                                        pgid = os.getpgid(popen.pid)
 
580
                                        os.killpg(pgid, signal.SIGTERM)  # Terminate the process
569
581
                                        time.sleep(0.1)
570
582
                                        retcode = popen.poll()
571
583
                                        if retcode is None: # Still going...
572
 
                                                os.kill(popen.pid, signal.SIGKILL) # Kill the process
 
584
                                                os.killpg(pgid, signal.SIGKILL)  # Kill the process
573
585
                                                time.sleep(0.1)
574
586
                                                retcode = popen.poll()
575
587
                        except OSError, e:
602
614
                                                        % (retcode, msg % locals()))
603
615
                        return False
604
616
                raise RuntimeError("Command execution failed: %s" % realCmd)
605
 
        
 
617