diff --git a/knockknock-daemon.py b/knockknock-daemon.py index dde23d2..6736f04 100644 --- a/knockknock-daemon.py +++ b/knockknock-daemon.py @@ -23,7 +23,7 @@ """ -import os, sys, pwd, grp, importlib +import os, sys, pwd, grp from knockknock.LogFile import LogFile from knockknock.LogJournald import JournalReader from knockknock.Profiles import Profiles @@ -47,13 +47,24 @@ def checkConfiguration(): print "/etc/knockknock.d/profiles/ does not exist. You need to setup your profiles first..." sys.exit(3) + # Retreive the system init type from /proc with open('/proc/1/status', 'r') as f: global initprocname - initprocname = f.readline().split[1] - - if initprocname == "systemd" and importlib.util.find_spec("systemd") is None: - print "Your init system was detected as systemd but the python systemd module is not installed. You need to install it first..." - sys.exit(3) + initprocname = f.readline().split()[1] + + # Verify whether or not the python-systemd dependency is required as well + # as whether or not it is fulfilled (optimistically written with python3 + # support) + if (sys.version_info > (3, 0)): + import importlib + if initprocname == "systemd" and importlib.util.find_spec("systemd") is None: + print "Your init system was detected as systemd but the python systemd module is not installed. You need to install it first..." + sys.exit(3) + else: + import pkgutil + if initprocname == "systemd" and pkgutil.find_loader("systemd") is None: + print "Your init system was detected as systemd but the python systemd module is not installed. You need to install it first..." + sys.exit(3) def dropPrivileges(): nobody = pwd.getpwnam('nobody') @@ -69,12 +80,15 @@ def handleFirewall(input, config): def handleKnocks(output, profiles, config): dropPrivileges() + # Attempt to determine logging source here (since it shouldn't require + # elevated privileges to verify this information) based on the system + # init process if initprocname == "systemd": logSource = JournalReader() elif initprocname in ["init", "preinit"]: logSource = LogFile('/var/log/kern.log') else: - print "Failed to find logging source. Exiting" + print "Failed to find logging source for your init system. Exiting" sys.exit(3) portOpener = PortOpener(output, config.getDelay()) knockWatcher = KnockWatcher(config, logSource, profiles, portOpener) diff --git a/knockknock/LogJournald.py b/knockknock/LogJournald.py index f9f23c4..3ddba3b 100644 --- a/knockknock/LogJournald.py +++ b/knockknock/LogJournald.py @@ -1,3 +1,9 @@ +""" +Journald log reader event loop for knockknock-daemon. + +Contains the JournalReader class which takes no parameters and has 1 method: +(tail) +""" # Copyright (c) 2015 Jason Ritzke # # This program is free software; you can redistribute it and/or @@ -17,18 +23,32 @@ # import select +import time from systemd import journal -print(output) class JournalReader: + """ + Journald reader for knockknock-daemon. - def tail(self): - j = journal.Reader() - j.seek_tail() - j.add_match('_TRANSPORT=kernel') - p = select.poll() - p.register(j, j.get_events()) + Takes no parameters on initialization. Has a single event loop method + called tail that yields new messages in the kernel log. + """ - p.poll() - yield j.get_next()['MESSAGE'] + def __init__(self): + """Initalization method for JournalReader class.""" + self.j = journal.Reader() + self.j.seek_tail() + self.j.add_match('_TRANSPORT=kernel') + self.p = select.poll() + self.p.register(self.j, self.j.get_events()) + + def tail(self): + """Generator that yields messages from the kernel log.""" + while True: + self.p.poll() + line = self.j.get_next() + if 'MESSAGE' not in line: + time.sleep(.25) + else: + yield line['MESSAGE']