mirror of https://github.com/fail2ban/fail2ban
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
306 lines
9.0 KiB
306 lines
9.0 KiB
#!/usr/bin/env python |
|
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*- |
|
# vi: set ft=python sts=4 ts=4 sw=4 noet : |
|
|
|
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
|
|
__author__ = "Cyril Jaquier, Steven Hiscocks, Yaroslav Halchenko" |
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2008-2016 Fail2Ban Contributors" |
|
__license__ = "GPL" |
|
|
|
import platform |
|
|
|
import setuptools |
|
from setuptools import setup |
|
from setuptools.command.install import install |
|
from setuptools.command.install_scripts import install_scripts |
|
|
|
import os |
|
from os.path import isfile, join, isdir, realpath |
|
import re |
|
import sys |
|
import warnings |
|
from glob import glob |
|
|
|
from fail2ban.setup import updatePyExec |
|
from fail2ban.version import version |
|
|
|
source_dir = os.path.realpath(os.path.dirname( |
|
# __file__ seems to be overwritten sometimes on some python versions (e.g. bug of 2.6 by running under cProfile, etc.): |
|
sys.argv[0] if os.path.basename(sys.argv[0]) == 'setup.py' else __file__ |
|
)) |
|
|
|
with_tests = True |
|
|
|
# Wrapper to install python binding (to current python version): |
|
class install_scripts_f2b(install_scripts): |
|
|
|
def get_outputs(self): |
|
outputs = install_scripts.get_outputs(self) |
|
# setup.py --dry-run install: |
|
dry_run = not outputs |
|
self.update_scripts(dry_run) |
|
if dry_run: |
|
#bindir = self.install_dir |
|
bindir = self.build_dir |
|
print(('creating fail2ban-python binding -> %s (dry-run, real path can be different)' % (bindir,))) |
|
print(('Copying content of %s to %s' % (self.build_dir, self.install_dir))); |
|
return outputs |
|
fn = None |
|
for fn in outputs: |
|
if os.path.basename(fn) == 'fail2ban-server': |
|
break |
|
bindir = os.path.dirname(fn) |
|
print(('creating fail2ban-python binding -> %s' % (bindir,))) |
|
updatePyExec(bindir) |
|
return outputs |
|
|
|
def update_scripts(self, dry_run=False): |
|
buildroot = os.path.dirname(self.build_dir) |
|
install_dir = self.install_dir |
|
try: |
|
# remove root-base from install scripts path: |
|
root = self.distribution.command_options['install']['root'][1] |
|
if install_dir.startswith(root): |
|
install_dir = install_dir[len(root):] |
|
except: # pragma: no cover |
|
print('WARNING: Cannot find root-base option, check the bin-path to fail2ban-scripts in "fail2ban.service" and "fail2ban-openrc.init".') |
|
|
|
scripts = ['fail2ban.service', 'fail2ban-openrc.init'] |
|
for script in scripts: |
|
print(('Creating %s/%s (from %s.in): @BINDIR@ -> %s' % (buildroot, script, script, install_dir))) |
|
with open(os.path.join(source_dir, 'files/%s.in' % script), 'r') as fn: |
|
lines = fn.readlines() |
|
fn = None |
|
if not dry_run: |
|
fn = open(os.path.join(buildroot, script), 'w') |
|
try: |
|
for ln in lines: |
|
ln = re.sub(r'@BINDIR@', lambda v: install_dir, ln) |
|
if dry_run: |
|
sys.stdout.write(' | ' + ln) |
|
continue |
|
fn.write(ln) |
|
finally: |
|
if fn: fn.close() |
|
if dry_run: |
|
print(' `') |
|
|
|
|
|
# Wrapper to specify fail2ban own options: |
|
class install_command_f2b(install): |
|
user_options = install.user_options + [ |
|
('without-tests', None, 'without tests files installation'), |
|
] |
|
def initialize_options(self): |
|
self.without_tests = not with_tests |
|
install.initialize_options(self) |
|
def finalize_options(self): |
|
if self.without_tests: |
|
self.distribution.scripts.remove('bin/fail2ban-testcases') |
|
|
|
self.distribution.packages.remove('fail2ban.tests') |
|
self.distribution.packages.remove('fail2ban.tests.action_d') |
|
|
|
del self.distribution.package_data['fail2ban.tests'] |
|
install.finalize_options(self) |
|
def run(self): |
|
install.run(self) |
|
|
|
|
|
# Update fail2ban-python env to current python version (where f2b-modules located/installed) |
|
updatePyExec(os.path.join(source_dir, 'bin')) |
|
|
|
if setuptools and "test" in sys.argv: |
|
import logging |
|
logSys = logging.getLogger("fail2ban") |
|
hdlr = logging.StreamHandler(sys.stdout) |
|
fmt = logging.Formatter("%(asctime)-15s %(message)s") |
|
hdlr.setFormatter(fmt) |
|
logSys.addHandler(hdlr) |
|
if set(["-q", "--quiet"]) & set(sys.argv): |
|
logSys.setLevel(logging.CRITICAL) |
|
warnings.simplefilter("ignore") |
|
sys.warnoptions.append("ignore") |
|
elif set(["-v", "--verbose"]) & set(sys.argv): |
|
logSys.setLevel(logging.DEBUG) |
|
else: |
|
logSys.setLevel(logging.INFO) |
|
elif "test" in sys.argv: |
|
print("python distribute required to execute fail2ban tests") |
|
print("") |
|
|
|
# if build without tests: |
|
if "build" in sys.argv: |
|
if "--without-tests" in sys.argv: |
|
with_tests = False |
|
sys.argv.remove("--without-tests") |
|
|
|
longdesc = ''' |
|
Fail2Ban scans log files like /var/log/pwdfail or |
|
/var/log/apache/error_log and bans IP that makes |
|
too many password failures. It updates firewall rules |
|
to reject the IP address or executes user defined |
|
commands.''' |
|
|
|
if setuptools: |
|
setup_extra = { |
|
'test_suite': "fail2ban.tests.utils.gatherTests", |
|
} |
|
else: |
|
setup_extra = {} |
|
|
|
data_files_extra = [] |
|
if os.path.exists('/var/run'): |
|
# if we are on the system with /var/run -- we are to use it for having fail2ban/ |
|
# directory there for socket file etc. |
|
# realpath is used to possibly resolve /var/run -> /run symlink |
|
data_files_extra += [(realpath('/var/run/fail2ban'), '')] |
|
|
|
# Installing documentation files only under Linux or other GNU/ systems |
|
# (e.g. GNU/kFreeBSD), since others might have protective mechanisms forbidding |
|
# installation there (see e.g. #1233) |
|
platform_system = platform.system().lower() |
|
doc_files = ['README.md', 'DEVELOP', 'FILTERS', 'doc/run-rootless.txt'] |
|
if platform_system in ('solaris', 'sunos'): |
|
doc_files.append('README.Solaris') |
|
if platform_system in ('linux', 'solaris', 'sunos') or platform_system.startswith('gnu'): |
|
data_files_extra.append( |
|
('/usr/share/doc/fail2ban', doc_files) |
|
) |
|
|
|
|
|
setup( |
|
name = "fail2ban", |
|
version = version, |
|
description = "Ban IPs that make too many password failures", |
|
long_description = longdesc, |
|
author = "Cyril Jaquier & Fail2Ban Contributors", |
|
author_email = "cyril.jaquier@fail2ban.org", |
|
url = "http://www.fail2ban.org", |
|
license = "GPL", |
|
platforms = "Posix", |
|
cmdclass = { |
|
'install_scripts': install_scripts_f2b, 'install': install_command_f2b |
|
}, |
|
scripts = [ |
|
'bin/fail2ban-client', |
|
'bin/fail2ban-server', |
|
'bin/fail2ban-regex', |
|
# 'bin/fail2ban-python', -- link (binary), will be installed via install_scripts_f2b wrapper |
|
] + [ |
|
'bin/fail2ban-testcases', |
|
] if with_tests else [], |
|
packages = [ |
|
'fail2ban', |
|
'fail2ban.client', |
|
'fail2ban.compat', |
|
'fail2ban.server', |
|
] + [ |
|
'fail2ban.tests', |
|
'fail2ban.tests.action_d', |
|
] if with_tests else [], |
|
package_data = { |
|
'fail2ban.tests': |
|
[ join(w[0], f).replace("fail2ban/tests/", "", 1) |
|
for w in os.walk('fail2ban/tests/files') |
|
for f in w[2]] + |
|
[ join(w[0], f).replace("fail2ban/tests/", "", 1) |
|
for w in os.walk('fail2ban/tests/config') |
|
for f in w[2]] + |
|
[ join(w[0], f).replace("fail2ban/tests/", "", 1) |
|
for w in os.walk('fail2ban/tests/action_d') |
|
for f in w[2]] |
|
} if with_tests else {}, |
|
data_files = [ |
|
('/etc/fail2ban', |
|
glob("config/*.conf") |
|
), |
|
('/etc/fail2ban/filter.d', |
|
glob("config/filter.d/*.conf") |
|
), |
|
('/etc/fail2ban/filter.d/ignorecommands', |
|
[p for p in glob("config/filter.d/ignorecommands/*") if isfile(p)] |
|
), |
|
('/etc/fail2ban/action.d', |
|
glob("config/action.d/*.conf") + |
|
glob("config/action.d/*.py") |
|
), |
|
('/etc/fail2ban/fail2ban.d', |
|
'' |
|
), |
|
('/etc/fail2ban/jail.d', |
|
'' |
|
), |
|
('/var/lib/fail2ban', |
|
'' |
|
), |
|
] + data_files_extra, |
|
**setup_extra |
|
) |
|
|
|
# Do some checks after installation |
|
# Search for obsolete files. |
|
obsoleteFiles = [] |
|
elements = { |
|
"/etc/": |
|
[ |
|
"fail2ban.conf" |
|
], |
|
"/usr/bin/": |
|
[ |
|
"fail2ban.py" |
|
], |
|
"/usr/lib/fail2ban/": |
|
[ |
|
"version.py", |
|
"protocol.py" |
|
] |
|
} |
|
|
|
for directory in elements: |
|
for f in elements[directory]: |
|
path = join(directory, f) |
|
if isfile(path): |
|
obsoleteFiles.append(path) |
|
|
|
if obsoleteFiles: |
|
print("") |
|
print("Obsolete files from previous Fail2Ban versions were found on " |
|
"your system.") |
|
print("Please delete them:") |
|
print("") |
|
for f in obsoleteFiles: |
|
print(("\t" + f)) |
|
print("") |
|
|
|
if isdir("/usr/lib/fail2ban"): |
|
print("") |
|
print("Fail2ban is not installed under /usr/lib anymore. The new " |
|
"location is under /usr/share. Please remove the directory " |
|
"/usr/lib/fail2ban and everything under this directory.") |
|
print("") |
|
|
|
# Update config file |
|
if sys.argv[1] == "install": |
|
print("") |
|
print("Please do not forget to update your configuration files.") |
|
print("They are in \"/etc/fail2ban/\".") |
|
print("") |
|
print("You can also install systemd service-unit file from \"build/fail2ban.service\"") |
|
print("resp. corresponding init script from \"files/*-initd\".") |
|
print("")
|
|
|