plaso-rubanetra/plaso/parsers/interface.py
2020-04-06 18:48:34 +02:00

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