#! /usr/bin/env python
import os, string, select, syslog
import audit, traceback
import AuditMsg
import subprocess, signal
PLUGIN_DIRS = ["/usr/lib/audit", "/usr/lib32/audit"]
import glob

HUP=False
def huphandler(signum, frame):
    global HUP
    HUP=True
    
class Plugin:
    def __init__(self, cmd):
        self.cmd = cmd
        self.sub_process = None

    def run(self):
        self.sub_process = subprocess.Popen(self.cmd, \
            stdin=subprocess.PIPE, stdout=None, stderr=None, \
            close_fds=True, shell=True)
        self.stdin = self.sub_process.stdin
        self.pid = self.sub_process.pid

    def stop(self):
        self.stdin.close()

    def get_pid(self):
        if self.subprocess is None:
            return None
        return self.subprocess.pid
        
    def get_stdin(self):
        if self.subprocess is None:
            return None
        return self.subprocess.stdin
        
    pid   = property(get_pid)
    stdin = property(get_stdin)
        
class audit_dispatcher:
    def __init__(self):
        self.data = []
        self.plugins = []
        self.load_plugins()
        
    def plugin_exists(self, cmd):
        for p in self.plugins:
            if p.cmd == cmd:
                return True
        return False
        
    def load_plugins(self):
        new_plugins = self.get_plugins()
        for plugin in self.get_plugins():
            if not self.plugin_exists(plugin):
                syslog.syslog("Starting %s" %  plugin)
                p = Plugin(plugin)
                try:
                    p.run()
                    self.plugins.append(p)
                except OSError, e:
                    syslog.syslog("plugin %s failed to start: %s" % (plugin, e))
		except IOError,e:
                    syslog.syslog("plugin %s failed to start: IOError exception %s" % (plugin, e))

        for p in self.plugins:
            if p.cmd not in new_plugins:
                p.stop()
                self.plugins.remove(p)

    def get_plugins(self):
        plugins = []
        for dir in PLUGIN_DIRS:
            plugins.extend(glob.glob(os.path.join(dir, '*')))
        return plugins

    def add(self, msg):
        self.data.append(msg)
        
    def process(self):
        if len(self.data) > 0:
            msg=self.data.pop(0)
            try:
                for plugin in self.plugins:
                    #syslog.syslog("sending plugin %s: '%s'" % (plugin.cmd, msg.get_body()))
                    plugin.stdin.write(msg.binary())
            except IOError,e:
                syslog.syslog("plugin %s failed: IOError exception %s" % (plugin.cmd, e))
                self.plugins.remove(plugin)

            return 0
        else:
            return 500

    def run(self):
        global HUP
        sleep=500
        while 1:
            try:
                input,output, err = select.select([0],[], [], sleep)
                if 0 in input:
                    msg = AuditMsg.AuditMsg()                    
                    if not msg.read_from_fd(0):
                        syslog.syslog("Connection closing")
                        return
                    #syslog.syslog("Read Input: type=%d body='%s'" % (msg.get_msg_type(), msg.get_body()))
                    self.add(msg)
                    sleep=0
                else:
                    sleep=self.process()

            except select.error, e:
                if e[0] == 4:
                    if HUP:
                        syslog.syslog("HUP signal")
                        self.load_plugins()
                        HUP=False
                else:
                    syslog.syslog("select exception %s " % e)
                    return

            except TypeError, e:
                syslog.syslog("Type exception %s " % e)
                syslog.syslog(traceback.format_exc())

try:
    syslog.openlog("audispd")
    syslog.syslog("starting audispd")
    signal.signal(signal.SIGHUP, huphandler)
    dispatcher=audit_dispatcher()
    dispatcher.run()

except IOError,e:
    syslog.syslog("IOError exception %s" % e)
    syslog.syslog(traceback.format_exc())

except Exception, e:
    syslog.syslog("Unexpected exception %s " % e)
    syslog.syslog(traceback.format_exc())
   
except:
    syslog.syslog("Caught Exception")
    syslog.syslog(traceback.format_exc())
