import os
import shutil
import time
import logging
from constants import DENY_DELIMITER,ENTRY_DELIMITER
from loginattempt import AbusiveHosts
from util import parse_host
import plugin
from purgecounter import PurgeCounter
debug = logging.getLogger("denyfileutil").debug
info = logging.getLogger("denyfileutil").info
warn = logging.getLogger("denyfileutil").warn
class DenyFileUtilBase:
def __init__(self, deny_file, extra_file_id=""):
self.deny_file = deny_file
self.backup_file = "%s.%s.bak" % (deny_file, extra_file_id)
self.temp_file = "%s.%s.tmp" % (deny_file, extra_file_id)
def backup(self):
try:
shutil.copy(self.deny_file, self.backup_file)
except Exception, e:
warn(str(e))
def replace(self):
# overwrites deny_file with contents of temp_file
try:
os.rename(self.temp_file, self.deny_file)
except Exception, e:
print e
def remove_temp(self):
try:
os.unlink(self.temp_file)
except:
pass
def create_temp(self, data_list):
raise Exception, "Not Imlemented"
def get_data(self):
data = []
try:
fp = open(self.backup_file, "r")
data = fp.readlines()
fp.close()
except:
pass
return data
#################################################################################
class Migrate(DenyFileUtilBase):
def __init__(self, deny_file):
DenyFileUtilBase.__init__(self, deny_file, "migrate")
self.backup()
self.create_temp(self.get_data())
self.replace()
def create_temp(self, data):
try:
fp = open(self.temp_file, "w")
os.chmod(self.temp_file, 0644)
for line in data:
if line.find("#") != -1:
fp.write(line)
continue
line = line.strip()
if not line:
fp.write("\n")
continue
fp.write("%s %s%s%s\n" % (DENY_DELIMITER,
time.asctime(),
ENTRY_DELIMITER,
line))
fp.write("%s\n" % line)
fp.close()
except Exception, e:
raise e
#################################################################################
class UpgradeTo099(DenyFileUtilBase):
def __init__(self, deny_file):
DenyFileUtilBase.__init__(self, deny_file, "0.9.9")
self.backup()
self.create_temp(self.get_data())
self.replace()
def create_temp(self, data):
try:
fp = open(self.temp_file, "w")
for line in data:
if line.find("#") == 0:
fp.write(line)
continue
line = line.strip()
if not line:
fp.write("\n")
continue
delimiter_idx = line.find(DENY_DELIMITER)
if delimiter_idx == -1:
fp.write("%s\n" % line)
continue
entry = line[:delimiter_idx].strip()
fp.write("%s%s%s\n" % (line[delimiter_idx:],
ENTRY_DELIMITER,
entry))
fp.write("%s\n" % entry)
fp.close()
except Exception, e:
raise e
#################################################################################
class Purge(DenyFileUtilBase):
def __init__(self, prefs, cutoff):
deny_file = prefs.get('HOSTS_DENY')
DenyFileUtilBase.__init__(self, deny_file, "purge")
work_dir = prefs.get('WORK_DIR')
self.purge_threshold = prefs['PURGE_THRESHOLD']
self.purge_counter = PurgeCounter(prefs)
self.cutoff = long(time.time()) - cutoff
debug("relative cutoff: %ld (seconds)", cutoff)
debug("absolute cutoff: %ld (epoch)", self.cutoff)
info("purging entries older than: %s",
time.asctime(time.localtime(self.cutoff)))
self.backup()
purged_hosts = self.create_temp(self.get_data())
num_purged = len(purged_hosts)
if num_purged > 0:
self.replace()
abusive_hosts = AbusiveHosts(prefs)
abusive_hosts.purge_hosts(purged_hosts)
abusive_hosts.save_abusive_hosts()
self.purge_counter.increment(purged_hosts)
else:
self.remove_temp()
info("num entries purged: %d", num_purged)
plugin_purge = prefs.get('PLUGIN_PURGE')
if plugin_purge:
plugin.execute(plugin_purge, purged_hosts)
def create_temp(self, data):
purged_hosts = []
banned = self.purge_counter.get_banned_for_life()
try:
fp = open(self.temp_file, "w")
os.chmod(self.temp_file, 0644)
offset = 0
num_lines = len(data)
while offset < num_lines:
line = data[offset]
offset += 1
if not line.startswith(DENY_DELIMITER):
fp.write(line)
continue
else:
timestamp = None
try:
rest = line.lstrip(DENY_DELIMITER)
timestamp, host_verify = rest.split(ENTRY_DELIMITER)
tm = time.strptime(timestamp)
except Exception, e:
warn("Parse error -- Ignorning timestamp: %s for: %s", timestamp, line)
warn("exception: %s", str(e))
# ignoring bad time string
fp.write(line)
continue
epoch = long(time.mktime(tm))
#print entry, epoch, self.cutoff
if self.cutoff > epoch:
# this entry should be purged
entry = data[offset]
if host_verify != entry:
warn("%s purge verification failed: %s vs. %s",
self.deny_file,
host_verify.rstrip(),
entry.rstrip())
fp.write(line)
continue
host = parse_host(entry)
if host and host not in banned:
# purge
purged_hosts.append(host)
# increment offset past purged line
offset += 1
continue
else:
fp.write(line)
continue
fp.close()
except Exception, e:
raise e
return purged_hosts
|