public inbox for linux-audit@redhat.com
 help / color / mirror / Atom feed
* High-level audit parser module
@ 2007-07-16 18:01 John D. Ramsdell
  2007-08-09 19:42 ` John D. Ramsdell
  0 siblings, 1 reply; 2+ messages in thread
From: John D. Ramsdell @ 2007-07-16 18:01 UTC (permalink / raw)
  To: linux-audit

John,

I'm working on a high-level audit reading Python library built on top
of the auparse module.  I suspect it could be made to be useful to
others besides myself.  I have enclosed the generated documentation
for the relevant classes in my module.

If you think it could be generally useful, the key question is what
methods should be defined in the AuditEvent and AuditRecord classes.
Some of the current ones are too specific to my needs.

CLASSES
    
    class AuditEvent(__builtin__.list)
     |  AuditEvent(AuEvent)
     |  
     |  An audit event is represented as a list of AuditRecord's.  Each
     |  AuditRecord is a dictionary that represents one of the records
     |  that make up the event.
     |  
     |  Method resolution order:
     |      AuditEvent
     |      __builtin__.list
     |      __builtin__.object
     |  
     |  Methods defined here:
     |  
     |  __init__(self, timestamp)
     |  
     |  find_record_of_type(self, typ)
     |      Find record of type
     |      
     |      Returns a record in the event that has the given type.
     |      Returns None when there is no such record.
     |  
     |  find_value(self, name)
     |      Find a value
     |      
     |      Returns a value associated with the given name in some record
     |      in the event.  Raises KeyError if no field has the given name.
     |  
     |  get_timestamp(self)
     |      Get the timestamp associated with this event.
     |  
     |  path_name(self, item)
     |      Find name and security context in PATH record
     |      
     |      Return the name and the security context in a PATH record that
     |      matches the given item number.  Raises KeyError if PATH record
     |      cannot be found.
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  __dict__
     |      dictionary for instance variables (if defined)
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from __builtin__.list:

        !!! inherited methods omitted !!!
    
    class AuditLog(__builtin__.object)
     |  AuditLog(AuParser or file, bool)
     |  
     |  Encapsulates a log accessed by the auparse module.  It provides an
     |  interator to the log's events.  Each call to the next method of
     |  the interator returns an AuditEvent.  The boolean determines if
     |  numeric entities in fields are interpreted.
     |  
     |  Methods defined here:
     |  
     |  __init__(self, au, interpret=False)
     |  
     |  __iter__(self)
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  __dict__
     |      dictionary for instance variables (if defined)
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
    
    class AuditLogIter(__builtin__.object)
     |  AuditLogIter(AuditLog)
     |  
     |  An iterator for an audit log.
     |  
     |  Methods defined here:
     |  
     |  __init__(self, aulog)
     |  
     |  next(self)
     |      Returns an AuditEvent
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  __dict__
     |      dictionary for instance variables (if defined)
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
    
    class AuditRecord(__builtin__.dict)
     |  AuditRecord(AuditEvent)
     |  
     |  An audit record is a dictionary.
     |  
     |  Method resolution order:
     |      AuditRecord
     |      __builtin__.dict
     |      __builtin__.object
     |  
     |  Methods defined here:
     |  
     |  __init__(self, event)
     |  
     |  get_event(self)
     |      Get the event associated with this record.
     |  
     |  path_name_record(self, item)
     |      Find name and security context in PATH record
     |      
     |      Return the name and the security context in a PATH record that
     |      matches the given item number.  Raises KeyError if PATH record
     |      cannot be found.
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  __dict__
     |      dictionary for instance variables (if defined)
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from __builtin__.dict:

        !!! inherited methods omitted !!!

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: High-level audit parser module
  2007-07-16 18:01 High-level audit parser module John D. Ramsdell
@ 2007-08-09 19:42 ` John D. Ramsdell
  0 siblings, 0 replies; 2+ messages in thread
From: John D. Ramsdell @ 2007-08-09 19:42 UTC (permalink / raw)
  To: sgrubb, jdennis; +Cc: linux-audit

[-- Attachment #1: Type: text/plain, Size: 408 bytes --]

Enclosed is a patch that adds a high-level audit parser module to the
audit package.  The included Python script can be used in two ways.
It can be installed in the usual location and the module can be
imported into other programs.  One can also make a copy of the Python
source file, and modify the function that consumes a log to quickly
produce one-off scripts.

Use pydoc to obtain documentation.

John


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: auditparser module --]
[-- Type: text/x-patch, Size: 10362 bytes --]

diff -urN a/audit-1.5.6/bindings/python/auditparser.py.in b/audit-1.5.6/bindings/python/auditparser.py.in
--- a/audit-1.5.6/bindings/python/auditparser.py.in	1969-12-31 19:00:00.000000000 -0500
+++ b/audit-1.5.6/bindings/python/auditparser.py.in	2007-08-09 15:29:25.000000000 -0400
@@ -0,0 +1,270 @@
+#! /usr/bin/python -E
+
+"""A high-level parser for audit logs.
+
+Provides AuditLog, which produces an iteration of audit events as a
+sequence of dictionary objects.
+
+To produces a quick one-off audit processing script, copy this source
+file and then edit the run function to suit your needs.
+
+Package: @PACKAGE@
+Version: @VERSION@
+
+"""
+
+# Authors: John D. Ramsdell
+#
+# Copyright (C) 2007 The MITRE Corporation
+# see file 'COPYING' for use and warranty information
+#
+# This program 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; version 2 only
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import sys, getopt, auparse, os.path, copy, string
+
+# Log Parsing
+
+class AuditLog(object):
+    """AuditLog(AuParser or file, bool)
+
+    Encapsulates a log accessed by the auparse module.  It provides an
+    iterator to the log's events.  Each call to the next method of
+    the iterator returns an AuditEvent.  The boolean determines if
+    numeric entities in fields are interpreted.
+
+    """
+    def __init__(self, au, interpret = False):
+        if isinstance(au, file):
+            self.au = auparse.AuParser(auparse.AUSOURCE_FILE_POINTER, au)
+        else:
+            self.au = au
+        self.interpret = interpret
+
+    def __iter__(self):
+        return AuditLogIter(self)
+
+class AuditLogIter(object):
+    """AuditLogIter(AuditLog)
+
+    An iterator for an audit log.
+
+    """
+    def __init__(self, aulog):
+        self.au = aulog.au
+        self.filename = self.au.get_filename()
+        self.interpret = aulog.interpret
+
+    def next(self):
+        """Returns an AuditEvent
+
+        """
+        au = self.au
+        interpret = self.interpret
+        if not au.parse_next_event():
+            raise StopIteration()
+        event = AuditEvent(au.get_timestamp(), self.filename)
+        for i in range(au.get_num_records()):
+            record = AuditRecord(event, au.get_line_number())
+            for j in range(au.get_num_fields()):
+                name = au.get_field_name()
+                if interpret:
+                    value = au.interpret_field()
+                else:
+                    value = au.get_field_str()
+                record[name] = value
+                au.next_field()
+            event.append(record)
+            au.next_record()
+        return event
+
+class AuditEvent(list):
+    """AuditEvent(AuEvent, string)
+
+    An audit event is represented as a list of AuditRecord's.  Each
+    AuditRecord is a dictionary that represents one of the records
+    that make up the event.  The string is a filename giving the
+    source of the event.
+
+    """
+    def __init__(self, timestamp, filename = None):
+        self.timestamp = timestamp
+        self.filename = filename
+
+    def get_timestamp(self):
+        """Get the timestamp associated with this event."""
+        return self.timestamp
+
+    def get_filename(self):
+        """Get the filename associated with this event."""
+        return self.filename
+
+    def find_record_of_type(self, type):
+        """Find record of type
+
+        Returns a record in the event that has the given type.
+        Returns None when there is no such record.
+
+        """
+        for record in self:
+            try:
+                if record["type"] == type:
+                    return record
+            except KeyError:
+                pass
+        return None
+
+    def find_value(self, name):
+        """Find a value
+
+        Returns a value associated with the given name in some record
+        in the event.  Raises KeyError if no field has the given name.
+
+        """
+        for record in self:
+            try:
+                return record[name]
+            except KeyError:
+                pass
+        raise KeyError
+
+    def find_path_record(self, item):
+        """Find a PATH record for the given item.
+
+        Returns the PATH record for the given item.  Return None if
+        PATH record cannot be found.
+
+        """
+        item = str(item)                # Ensure item is a string
+        for record in self:
+            if record.is_path_record(item):
+                return record
+        return None
+
+class AuditRecord(dict):
+    """AuditRecord(AuditEvent, int)
+
+    An audit record is a dictionary.  The int is the line number
+    associated with the source of the record.
+
+    """
+    def __init__(self, event, line_number):
+        self.event = event
+        self.line_number = line_number
+
+    def get_event(self):
+        """Get the event associated with this record."""
+        return self.event
+
+    def get_line_number(self):
+        """Get the line number associated with this record."""
+        return self.line_number
+
+    def get_source(self):
+        """Get the source of this record as a string."""
+        serial = self.get_event().get_timestamp().serial
+        source = "%d (serial=%d)" % (self.line_number, serial)
+        filename = self.get_event().get_filename()
+        if filename:
+            return filename + ":" + source
+        else:
+            return source
+
+    def is_path_record(self, item):
+        """Is this a PATH record for the given item?"""
+        try:
+            return self["type"] == "PATH" and self["item"] == item
+        except KeyError:
+            return False
+
+def args2aulog():
+    """Make an AuditLog from command line arguments
+
+    Create an audit log object based on the command line arguments
+    passsed to this program.
+
+    Returns an AuditLog.
+
+    """
+    interpret = False                   # Event reading mode
+    output_file = None                  # Output file name for results
+    try:
+        long_opts = ["help", "interpret", "raw", "output="]
+        opts, args = getopt.getopt(sys.argv[1:], "hiro:", long_opts)
+    except getopt.GetoptError:
+        # Bad options
+        usage()
+        sys.exit(2)
+    for o, a in opts:
+        if o in ("-h", "--help"):
+            # Print help information
+            usage()
+            sys.exit(0)
+        elif o in ("-i", "--interpret"):
+            interpret = True
+        elif o in ("-r", "--raw"):
+            interpret = False
+        elif o in ("-o", "--output"):
+            # Record output file name
+            output_file = a
+    # Determine input source
+    if len(args) > 0:
+        au = auparse.AuParser(auparse.AUSOURCE_FILE_ARRAY, args)
+        sys.stdin.close()
+    else:
+        au = sys.stdin
+    # Open output file as standard output
+    if output_file:
+        sys.stdout.close()
+        try:
+            sys.stdout = file(output_file, 'w')
+        except IOError:
+            sys.stderr.write("cannot open %s for writing" % output_file)
+            sys.exit(1)
+    return AuditLog(au, interpret)
+
+def usage():
+    """Show usage
+
+    Print a ussage message that includes version information.
+
+    """
+    help = """Version: %s %s
+Usage: %s [OPTIONS] [FILE...]
+
+  -o FILE, --output=FILE     output to FILE (default is standard output)
+  -i,      --interpret       interpret numeric entities into text
+  -r       --raw             do not interpret numeric entities (default)
+  -h,      --help            print this message and exit
+
+With no FILEs, read from the standard input.
+"""
+    sys.stderr.write(help % ("@PACKAGE@", "@VERSION@", sys.argv[0]))
+
+# Consume a log
+
+def run(log):
+    """The main loop for consuming a log.  Modify this to suit your needs."""
+    for event in log:
+        print event
+
+def main():
+    """Main routine
+
+    Perform command line processing and then conume the log.
+
+    """
+    run(args2aulog())
+
+if __name__ == "__main__":
+    main()
diff -urN a/audit-1.5.6/bindings/python/Makefile.am b/audit-1.5.6/bindings/python/Makefile.am
--- a/audit-1.5.6/bindings/python/Makefile.am	2007-07-25 14:17:26.000000000 -0400
+++ b/audit-1.5.6/bindings/python/Makefile.am	2007-07-27 11:39:56.000000000 -0400
@@ -21,7 +21,7 @@
 # 
 
 CONFIG_CLEAN_FILES = Makefile.in *.loT *.rej *.orig
-EXTRA_DIST = setup.py auparse_python.c
+EXTRA_DIST = setup.py auparse_python.c auditparser.py
 
 all:
 	$(PYTHON) setup.py build
diff -urN a/audit-1.5.6/bindings/python/setup.py b/audit-1.5.6/bindings/python/setup.py
--- a/audit-1.5.6/bindings/python/setup.py	2007-05-01 18:06:23.000000000 -0400
+++ b/audit-1.5.6/bindings/python/setup.py	2007-07-27 11:54:34.000000000 -0400
@@ -11,3 +11,8 @@
       description = 'python binding for audit parsing (auparse)',
       ext_modules = [auparse])
 
+setup(name = 'auditparser',
+      version = '1.0',
+      description = 'high-level python binding for audit parsing',
+      py_modules = ['auditparser'])
+
diff -urN a/audit-1.5.6/configure.ac b/audit-1.5.6/configure.ac
--- a/audit-1.5.6/configure.ac	2007-07-23 14:39:31.000000000 -0400
+++ b/audit-1.5.6/configure.ac	2007-07-27 11:41:06.000000000 -0400
@@ -109,7 +109,7 @@
       AC_DEFINE(WITH_APPARMOR,1,[Define if you want to enable AppArmor events.])fi
 
 AC_CONFIG_SUBDIRS([system-config-audit])
-AC_OUTPUT(Makefile lib/Makefile auparse/Makefile auparse/test/Makefile src/Makefile src/mt/Makefile swig/Makefile docs/Makefile init.d/Makefile audisp/Makefile bindings/Makefile bindings/python/Makefile)
+AC_OUTPUT(Makefile lib/Makefile auparse/Makefile auparse/test/Makefile src/Makefile src/mt/Makefile swig/Makefile docs/Makefile init.d/Makefile audisp/Makefile bindings/Makefile bindings/python/Makefile bindings/python/auditparser.py)
 
 echo .
 echo "

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-08-09 19:42 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-07-16 18:01 High-level audit parser module John D. Ramsdell
2007-08-09 19:42 ` John D. Ramsdell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox