252 lines
7.6 KiB
Python
252 lines
7.6 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright 2012 The Plaso Project Authors.
|
|
# Please see the AUTHORS file for details on individual authors.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
"""This file contains a class to provide a parsing framework to plaso.
|
|
|
|
This class contains a base framework class for parsing fileobjects, and
|
|
also some implementations that extend it to provide a more comprehensive
|
|
parser.
|
|
"""
|
|
|
|
import abc
|
|
|
|
from plaso.parsers import manager
|
|
|
|
|
|
class BaseParser(object):
|
|
"""Class that implements the parser object interface."""
|
|
|
|
NAME = 'base_parser'
|
|
DESCRIPTION = u''
|
|
|
|
def _BuildParserChain(self, parser_chain=None):
|
|
"""Return the parser chain with the addition of the current parser.
|
|
|
|
Args:
|
|
parser_chain: Optional string containing the parsing chain up to this
|
|
point. The default is None.
|
|
|
|
Returns:
|
|
The parser chain, with the addition of the current parser.
|
|
"""
|
|
if not parser_chain:
|
|
return self.NAME
|
|
|
|
return u'/'.join([parser_chain, self.NAME])
|
|
|
|
@abc.abstractmethod
|
|
def Parse(self, parser_context, file_entry, parser_chain=None):
|
|
"""Parsers the file entry and extracts event objects.
|
|
|
|
This is the main function of the class, the one that actually
|
|
goes through the log file and parses each line of it to
|
|
produce a parsed line and a timestamp.
|
|
|
|
It also tries to verify the file structure and see if the class is capable
|
|
of parsing the file passed to the module. It will do so with series of tests
|
|
that should determine if the file is of the correct structure.
|
|
|
|
If the class is not capable of parsing the file passed to it an exception
|
|
should be raised, an exception of the type UnableToParseFile that indicates
|
|
the reason why the class does not parse it.
|
|
|
|
Args:
|
|
parser_context: A parser context object (instance of ParserContext).
|
|
file_entry: A file entry object (instance of dfvfs.FileEntry).
|
|
parser_chain: Optional string containing the parsing chain up to this
|
|
point. The default is None.
|
|
|
|
Raises:
|
|
NotImplementedError when not implemented.
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
@classmethod
|
|
def SupportsPlugins(cls):
|
|
"""Determines if a parser supports plugins.
|
|
|
|
Returns:
|
|
A boolean value indicating whether the parser supports plugins.
|
|
"""
|
|
return False
|
|
|
|
|
|
class BasePluginsParser(BaseParser):
|
|
"""Class that implements the parser with plugins object interface."""
|
|
|
|
NAME = 'base_plugin_parser'
|
|
DESCRIPTION = u''
|
|
|
|
# Every child class should define its own _plugin_classes dict.
|
|
# We don't define it here to make sure the plugins of different
|
|
# classes don't end up in the same dict.
|
|
# _plugin_classes = {}
|
|
_plugin_classes = None
|
|
|
|
@classmethod
|
|
def DeregisterPlugin(cls, plugin_class):
|
|
"""Deregisters a plugin class.
|
|
|
|
The plugin classes are identified based on their lower case name.
|
|
|
|
Args:
|
|
plugin_class: the class object of the plugin.
|
|
|
|
Raises:
|
|
KeyError: if plugin class is not set for the corresponding name.
|
|
"""
|
|
plugin_name = plugin_class.NAME.lower()
|
|
if plugin_name not in cls._plugin_classes:
|
|
raise KeyError(
|
|
u'Plugin class not set for name: {0:s}.'.format(
|
|
plugin_class.NAME))
|
|
|
|
del cls._plugin_classes[plugin_name]
|
|
|
|
@classmethod
|
|
def GetPluginNames(cls, parser_filter_string=None):
|
|
"""Retrieves the plugin names.
|
|
|
|
Args:
|
|
parser_filter_string: Optional parser filter string. The default is None.
|
|
|
|
Returns:
|
|
A list of plugin names.
|
|
"""
|
|
plugin_names = []
|
|
|
|
for plugin_name, _ in cls.GetPlugins(
|
|
parser_filter_string=parser_filter_string):
|
|
plugin_names.append(plugin_name)
|
|
|
|
return plugin_names
|
|
|
|
@classmethod
|
|
def GetPluginObjects(cls, parser_filter_string=None):
|
|
"""Retrieves the plugin objects.
|
|
|
|
Args:
|
|
parser_filter_string: Optional parser filter string. The default is None.
|
|
|
|
Returns:
|
|
A list of plugin objects (instances of BasePlugin).
|
|
"""
|
|
plugin_objects = []
|
|
|
|
for _, plugin_class in cls.GetPlugins(
|
|
parser_filter_string=parser_filter_string):
|
|
plugin_object = plugin_class()
|
|
plugin_objects.append(plugin_object)
|
|
|
|
return plugin_objects
|
|
|
|
@classmethod
|
|
def GetPlugins(cls, parser_filter_string=None):
|
|
"""Retrieves the registered plugins.
|
|
|
|
Args:
|
|
parser_filter_string: Optional parser filter string. The default is None.
|
|
|
|
Yields:
|
|
A tuple that contains the uniquely identifying name of the plugin
|
|
and the plugin class (subclass of BasePlugin).
|
|
"""
|
|
if parser_filter_string:
|
|
includes, excludes = manager.ParsersManager.GetFilterListsFromString(
|
|
parser_filter_string)
|
|
else:
|
|
includes = None
|
|
excludes = None
|
|
|
|
for plugin_name, plugin_class in cls._plugin_classes.iteritems():
|
|
if excludes and plugin_name in excludes:
|
|
continue
|
|
|
|
if includes and plugin_name not in includes:
|
|
continue
|
|
|
|
yield plugin_name, plugin_class
|
|
|
|
@abc.abstractmethod
|
|
def Parse(self, parser_context, file_entry, parser_chain=None):
|
|
"""Parsers the file entry and extracts event objects.
|
|
|
|
This is the main function of the class, the one that actually
|
|
goes through the log file and parses each line of it to
|
|
produce a parsed line and a timestamp.
|
|
|
|
It also tries to verify the file structure and see if the class is capable
|
|
of parsing the file passed to the module. It will do so with series of tests
|
|
that should determine if the file is of the correct structure.
|
|
|
|
If the class is not capable of parsing the file passed to it an exception
|
|
should be raised, an exception of the type UnableToParseFile that indicates
|
|
the reason why the class does not parse it.
|
|
|
|
Args:
|
|
parser_context: A parser context object (instance of ParserContext).
|
|
file_entry: A file entry object (instance of dfvfs.FileEntry).
|
|
parser_chain: Optional string containing the parsing chain up to this
|
|
point. The default is None.
|
|
|
|
Raises:
|
|
NotImplementedError when not implemented.
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
@classmethod
|
|
def RegisterPlugin(cls, plugin_class):
|
|
"""Registers a plugin class.
|
|
|
|
The plugin classes are identified based on their lower case name.
|
|
|
|
Args:
|
|
plugin_class: the class object of the plugin.
|
|
|
|
Raises:
|
|
KeyError: if plugin class is already set for the corresponding name.
|
|
"""
|
|
plugin_name = plugin_class.NAME.lower()
|
|
if plugin_name in cls._plugin_classes:
|
|
raise KeyError((
|
|
u'Plugin class already set for name: {0:s}.').format(
|
|
plugin_class.NAME))
|
|
|
|
cls._plugin_classes[plugin_name] = plugin_class
|
|
|
|
@classmethod
|
|
def RegisterPlugins(cls, plugin_classes):
|
|
"""Registers plugin classes.
|
|
|
|
Args:
|
|
plugin_classes: a list of class objects of the plugins.
|
|
|
|
Raises:
|
|
KeyError: if plugin class is already set for the corresponding name.
|
|
"""
|
|
for plugin_class in plugin_classes:
|
|
cls.RegisterPlugin(plugin_class)
|
|
|
|
@classmethod
|
|
def SupportsPlugins(cls):
|
|
"""Determines if a parser supports plugins.
|
|
|
|
Returns:
|
|
A boolean value indicating whether the parser supports plugins.
|
|
"""
|
|
return True
|