Ejemplo n.º 1
0
  def ParseArguments(self, arguments):
    """Parses the command line arguments.

    Args:
      arguments (list[str]): command line arguments.

    Raises:
      CommandLineParseError: If arguments could not be parsed.
    """
    help_text = self._GenerateHelpText()

    argument_parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=help_text)

    self._AddRecipeOptions(argument_parser)

    self._command_line_options = argument_parser.parse_args(arguments)

    if not getattr(self._command_line_options, 'recipe', None):
      error_message = '\nPlease specify a recipe.\n' + help_text
      raise errors.CommandLineParseError(error_message)

    self._recipe = self._command_line_options.recipe

    self._state = DFTimewolfState(config.Config)
    logger.info('Loading recipe {0:s}...'.format(self._recipe['name']))
    # Raises errors.RecipeParseError on error.
    self._state.LoadRecipe(self._recipe)

    number_of_modules = len(self._recipe['modules'])
    logger.info('Loaded recipe {0:s} with {1:d} modules'.format(
        self._recipe['name'], number_of_modules))

    self._state.command_line_options = vars(self._command_line_options)
Ejemplo n.º 2
0
  def ParseArguments(self, arguments):
    """Parses the command line arguments.

    Args:
      arguments (list[str]): command line arguments.

    Returns:
      bool: True if the arguments were successfully parsed.
    """
    help_text = self._GenerateHelpText()

    argument_parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=help_text)

    self._AddRecipeOptions(argument_parser)

    self._command_line_options = argument_parser.parse_args(arguments)
    self._recipe = self._command_line_options.recipe

    self._state = DFTimewolfState(config.Config)
    print('Loading recipe...')
    self._state.load_recipe(self._recipe)

    number_of_modules = len(self._recipe['modules'])
    print('Loaded recipe {0:s} with {1:d} modules'.format(
        self._recipe['name'], number_of_modules))

    return True
Ejemplo n.º 3
0
def main():
    """Main function for DFTimewolf."""
    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=generate_help())

    subparsers = parser.add_subparsers()

    for registered_recipe in config.Config.get_registered_recipes():
        recipe, recipe_args, documentation = registered_recipe
        subparser = subparsers.add_parser(
            recipe['name'],
            formatter_class=utils.DFTimewolfFormatterClass,
            description='{0:s}'.format(documentation))
        subparser.set_defaults(recipe=recipe)
        for switch, help_text, default in recipe_args:
            subparser.add_argument(switch, help=help_text, default=default)
        # Override recipe defaults with those specified in Config
        # so that they can in turn be overridden in the commandline
        subparser.set_defaults(**config.Config.get_extra())

    args = parser.parse_args()
    recipe = args.recipe

    # Thread all collectors.
    state = DFTimewolfState()

    for module_description in recipe['modules']:
        # Combine CLI args with args from the recipe description
        new_args = utils.import_args_from_dict(module_description['args'],
                                               vars(args), config.Config)

        # Create the module object and start processing
        module_name = module_description['name']
        print('Running module {0:s}'.format(module_name))
        module = config.Config.get_module(module_name)(state)
        module.setup(**new_args)
        state.check_errors()
        try:
            module.process()
        except DFTimewolfError as error:
            state.add_error(error.message, critical=True)

        # Check for eventual errors and clean up after each round.
        state.check_errors()
        state.cleanup()

    print('Recipe executed successfully.')
Ejemplo n.º 4
0
def main():
    """Main function for DFTimewolf."""
    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=generate_help())

    subparsers = parser.add_subparsers()

    for registered_recipe in config.Config.get_registered_recipes():
        recipe, recipe_args, documentation = registered_recipe
        subparser = subparsers.add_parser(
            recipe['name'],
            formatter_class=utils.DFTimewolfFormatterClass,
            description='{0:s}'.format(documentation))
        subparser.set_defaults(recipe=recipe)
        for switch, help_text, default in recipe_args:
            subparser.add_argument(switch, help=help_text, default=default)
        # Override recipe defaults with those specified in Config
        # so that they can in turn be overridden in the commandline
        subparser.set_defaults(**config.Config.get_extra())

    args = parser.parse_args()
    recipe = args.recipe

    state = DFTimewolfState(config.Config)
    print('Loading recipes...')
    state.load_recipe(recipe)
    print('Loaded recipe {0:s} with {1:d} modules'.format(
        recipe['name'], len(recipe['modules'])))

    print('Setting up modules...')
    state.setup_modules(args)
    print('Modules successfully set up!')

    print('Running modules...')
    state.run_modules()
    print('Recipe {0:s} executed successfully.'.format(recipe['name']))
Ejemplo n.º 5
0
class DFTimewolfTool(object):
  """DFTimewolf tool."""

  _DEFAULT_DATA_FILES_PATH = os.path.join(
      os.sep, 'usr', 'local', 'share', 'dftimewolf')

  def __init__(self):
    """Initializes a DFTimewolf tool."""
    super(DFTimewolfTool, self).__init__()
    self._command_line_options = None
    self._data_files_path = None
    self._recipes_manager = recipes_manager.RecipesManager()
    self._recipe = None
    self._state = None

    self._DetermineDataFilesPath()

  @property
  def state(self):
    """Returns the internal state object."""
    return self._state

  def _AddRecipeOptions(self, argument_parser):
    """Adds the recipe options to the argument group.

    Args:
      argument_parser (argparse.ArgumentParser): argparse argument parser.
    """
    subparsers = argument_parser.add_subparsers()

    for recipe in self._recipes_manager.GetRecipes():
      description = recipe.description
      subparser = subparsers.add_parser(
          recipe.name, formatter_class=utils.DFTimewolfFormatterClass,
          description=description)
      subparser.set_defaults(recipe=recipe.contents)

      for switch, help_text, default in recipe.args:
        if isinstance(default, bool):
          subparser.add_argument(switch, help=help_text, default=default,
                                 action='store_true')
        else:
          subparser.add_argument(switch, help=help_text, default=default)

      # Override recipe defaults with those specified in Config
      # so that they can in turn be overridden in the commandline
      subparser.set_defaults(**config.Config.GetExtra())

  def _DetermineDataFilesPath(self):
    """Determines the data files path.

    Data path is specified in the DFTIMEWOLF_DATA environment variable. If the
    variable is not specified, dfTimewolf checks if any of the following
    locations are valid:

    * Cloned repository base
    * Local package data files
    * sys.prefix
    * Hardcoded default /usr/local/share
    """

    data_files_path = os.environ.get('DFTIMEWOLF_DATA')

    if not data_files_path or not os.path.isdir(data_files_path):
      # Figure out if the script is running out of a cloned repository
      data_files_path = os.path.realpath(__file__)
      data_files_path = os.path.dirname(data_files_path)
      data_files_path = os.path.dirname(data_files_path)
      data_files_path = os.path.dirname(data_files_path)
      data_files_path = os.path.join(data_files_path, 'data')

      # Use local package data files (python setup.py install)
      if not os.path.isdir(data_files_path):
        data_files_path = os.path.dirname(data_files_path)
        data_files_path = os.path.join(data_files_path, 'share', 'dftimewolf')

      # Use sys.prefix for user installs (e.g. pip install ...)
      if not os.path.isdir(data_files_path):
        data_files_path = os.path.join(sys.prefix, 'share', 'dftimewolf')

      # If all else fails, fall back to hardcoded default
      if not os.path.isdir(data_files_path):
        logger.debug('{0:s} not found, defaulting to /usr/local/share'.format(
            data_files_path))
        data_files_path = self._DEFAULT_DATA_FILES_PATH

    logger.debug("Recipe data path: {0:s}".format(data_files_path))
    self._data_files_path = data_files_path

  def _GenerateHelpText(self):
    """Generates help text with alphabetically sorted recipes.

    Returns:
      str: help text.
    """
    recipes = self._recipes_manager.GetRecipes()
    if not recipes:
      help_text = '\nNo recipes found.'
    else:
      help_text = '\nAvailable recipes:\n\n'
      for recipe in recipes:
        short_description = recipe.contents.get(
            'short_description', 'No description')
        help_text += ' {0:<35s}{1:s}\n'.format(recipe.name, short_description)

    return help_text

  def _LoadConfigurationFromFile(self, configuration_file_path):
    """Loads a configuration from file.

    Args:
      configuration_file_path (str): path of the configuration file.
    """
    try:
      if config.Config.LoadExtra(configuration_file_path):
        logger.debug('Configuration loaded from: {0:s}'.format(
            configuration_file_path))

    except errors.BadConfigurationError as exception:
      logger.warning('{0!s}'.format(exception))

  def LoadConfiguration(self):
    """Loads the configuration.

    The following paths are tried. Values loaded last take precedence.

    * <_data_files_path>/config.json
    * /etc/dftimewolf.conf
    * /usr/share/dftimewolf/dftimewolf.conf
    * ~/.dftimewolfrc
    * If set, wherever the DFTIMEWOLF_CONFIG environment variable points to.

    """
    configuration_file_path = os.path.join(self._data_files_path, 'config.json')
    self._LoadConfigurationFromFile(configuration_file_path)

    configuration_file_path = os.path.join('/', 'etc', 'dftimewolf.conf')
    self._LoadConfigurationFromFile(configuration_file_path)

    configuration_file_path = os.path.join(
        '/', 'usr', 'share', 'dftimewolf', 'dftimewolf.conf')
    self._LoadConfigurationFromFile(configuration_file_path)

    user_directory = os.path.expanduser('~')
    configuration_file_path = os.path.join(user_directory, '.dftimewolfrc')
    self._LoadConfigurationFromFile(configuration_file_path)

    env_config = os.environ.get('DFTIMEWOLF_CONFIG')
    if env_config:
      self._LoadConfigurationFromFile(env_config)

  def ParseArguments(self, arguments):
    """Parses the command line arguments.

    Args:
      arguments (list[str]): command line arguments.

    Raises:
      CommandLineParseError: If arguments could not be parsed.
    """
    help_text = self._GenerateHelpText()

    argument_parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=help_text)

    self._AddRecipeOptions(argument_parser)

    self._command_line_options = argument_parser.parse_args(arguments)

    if not getattr(self._command_line_options, 'recipe', None):
      error_message = '\nPlease specify a recipe.\n' + help_text
      raise errors.CommandLineParseError(error_message)

    self._recipe = self._command_line_options.recipe

    self._state = DFTimewolfState(config.Config)
    logger.info('Loading recipe {0:s}...'.format(self._recipe['name']))
    # Raises errors.RecipeParseError on error.
    self._state.LoadRecipe(self._recipe)

    number_of_modules = len(self._recipe['modules'])
    logger.info('Loaded recipe {0:s} with {1:d} modules'.format(
        self._recipe['name'], number_of_modules))

    self._state.command_line_options = vars(self._command_line_options)

  def RunPreflights(self):
    """Runs preflight modules."""
    logger.info('Running preflights...')
    self._state.RunPreflights()

  def ReadRecipes(self):
    """Reads the recipe files."""
    if os.path.isdir(self._data_files_path):
      recipes_path = os.path.join(self._data_files_path, 'recipes')
      if os.path.isdir(recipes_path):
        self._recipes_manager.ReadRecipesFromDirectory(recipes_path)

  def RunModules(self):
    """Runs the modules."""
    logger.info('Running modules...')
    self._state.RunModules()
    logger.info('Recipe {0:s} executed successfully!'.format(
        self._recipe['name']))

  def SetupModules(self):
    """Sets up the modules."""
    # TODO: refactor to only load modules that are used by the recipe.

    logger.info('Setting up modules...')
    self._state.SetupModules()
    logger.info('Modules successfully set up!')

  def CleanUpPreflights(self):
    """Calls the preflight's CleanUp functions."""
    self._state.CleanUpPreflights()
Ejemplo n.º 6
0
class DFTimewolfTool(object):
    """DFTimewolf tool."""

    _DEFAULT_DATA_FILES_PATH = os.path.join('/', 'usr', 'local', 'share',
                                            'dftimewolf')

    def __init__(self):
        """Initializes a DFTimewolf tool."""
        super(DFTimewolfTool, self).__init__()
        self._command_line_options = None
        self._data_files_path = None
        self._recipes_manager = recipes_manager.RecipesManager()
        self._recipe = None
        self._state = None

        self._DetermineDataFilesPath()

    def _AddRecipeOptions(self, argument_parser):
        """Adds the recipe options to the argument group.

    Args:
      argument_parser (argparse.ArgumentParser): argparse argument parser.
    """
        subparsers = argument_parser.add_subparsers()

        for recipe in self._recipes_manager.GetRecipes():
            description = recipe.description
            subparser = subparsers.add_parser(
                recipe.name,
                formatter_class=utils.DFTimewolfFormatterClass,
                description=description)
            subparser.set_defaults(recipe=recipe.contents)

            for switch, help_text, default in recipe.args:
                if isinstance(default, bool):
                    subparser.add_argument(switch,
                                           help=help_text,
                                           default=default,
                                           action='store_true')
                else:
                    subparser.add_argument(switch,
                                           help=help_text,
                                           default=default)

            # Override recipe defaults with those specified in Config
            # so that they can in turn be overridden in the commandline
            subparser.set_defaults(**config.Config.GetExtra())

    def _DetermineDataFilesPath(self):
        """Determines the data files path."""

        # Figure out if the script is running out of a cloned repository
        data_files_path = os.path.realpath(__file__)
        data_files_path = os.path.dirname(data_files_path)
        data_files_path = os.path.dirname(data_files_path)
        data_files_path = os.path.dirname(data_files_path)
        data_files_path = os.path.join(data_files_path, 'data')

        # Use sys.prefix for user installs (e.g. pip install ...)
        if not os.path.isdir(data_files_path):
            data_files_path = os.path.join(sys.prefix, 'share', 'dftimewolf')

        # If all else fails, fall back to hardcoded default
        if not os.path.isdir(data_files_path):
            data_files_path = self._DEFAULT_DATA_FILES_PATH

        print('Data files read from', data_files_path)
        self._data_files_path = data_files_path

    def _GenerateHelpText(self):
        """Generates help text with alphabetically sorted recipes.

    Returns:
      str: help text.
    """
        recipes = self._recipes_manager.GetRecipes()
        if not recipes:
            help_text = '\nNo recipes found.'
        else:
            help_text = '\nAvailable recipes:\n\n'
            for recipe in recipes:
                short_description = recipe.contents.get(
                    'short_description', 'No description')
                help_text += ' {0:<35s}{1:s}\n'.format(recipe.name,
                                                       short_description)

        return help_text

    def _LoadConfigurationFromFile(self, configuration_file_path):
        """Loads a configuration from file.

    Args:
      configuration_file_path (str): path of the configuration file.
    """
        try:
            if config.Config.LoadExtra(configuration_file_path):
                sys.stderr.write('Configuration loaded from: {0:s}\n'.format(
                    configuration_file_path))

        except errors.BadConfigurationError as exception:
            sys.stderr.write('{0!s}'.format(exception))

    def LoadConfiguration(self):
        """Loads the configuration."""
        configuration_file_path = os.path.join(self._data_files_path,
                                               'config.json')
        self._LoadConfigurationFromFile(configuration_file_path)

        user_directory = os.path.expanduser('~')
        configuration_file_path = os.path.join(user_directory, '.dftimewolfrc')
        self._LoadConfigurationFromFile(configuration_file_path)

        configuration_file_path = os.path.join('/', 'etc', 'dftimewolf.conf')
        self._LoadConfigurationFromFile(configuration_file_path)

        configuration_file_path = os.path.join('/', 'usr', 'share',
                                               'dftimewolf', 'dftimewolf.conf')
        self._LoadConfigurationFromFile(configuration_file_path)

    def ParseArguments(self, arguments):
        """Parses the command line arguments.

    Args:
      arguments (list[str]): command line arguments.

    Raises:
      CommandLineParseError: If arguments could not be parsed.
    """
        help_text = self._GenerateHelpText()

        argument_parser = argparse.ArgumentParser(
            formatter_class=argparse.RawDescriptionHelpFormatter,
            description=help_text)

        self._AddRecipeOptions(argument_parser)

        self._command_line_options = argument_parser.parse_args(arguments)

        if not getattr(self._command_line_options, 'recipe', None):
            error_message = '\nPlease specify a recipe.\n' + help_text
            raise errors.CommandLineParseError(error_message)

        self._recipe = self._command_line_options.recipe

        self._state = DFTimewolfState(config.Config)
        print('Loading recipe...')
        # Raises errors.RecipeParseError on error.
        self._state.LoadRecipe(self._recipe)

        number_of_modules = len(self._recipe['modules'])
        print('Loaded recipe {0:s} with {1:d} modules'.format(
            self._recipe['name'], number_of_modules))

        self._state.command_line_options = vars(self._command_line_options)

    def RunPreflights(self):
        """Runs preflight modules."""
        print('Running preflights...')
        self._state.RunPreflights()

    def ReadRecipes(self):
        """Reads the recipe files."""
        if os.path.isdir(self._data_files_path):
            recipes_path = os.path.join(self._data_files_path, 'recipes')
            if os.path.isdir(recipes_path):
                self._recipes_manager.ReadRecipesFromDirectory(recipes_path)

    def RunModules(self):
        """Runs the modules."""
        print('Running modules...')
        self._state.RunModules()
        print('Recipe {0:s} executed successfully.'.format(
            self._recipe['name']))

    def SetupModules(self):
        """Sets up the modules."""
        # TODO: refactor to only load modules that are used by the recipe.

        print('Setting up modules...')
        self._state.SetupModules()
        print('Modules successfully set up!')
Ejemplo n.º 7
0
class DFTimewolfTool(object):
  """DFTimewolf tool."""

  _DEFAULT_DATA_FILES_PATH = os.path.join('/', 'usr', 'share', 'dftimewolf')

  def __init__(self):
    """Initializes a DFTimewolf tool."""
    super(DFTimewolfTool, self).__init__()
    self._command_line_options = None
    self._data_files_path = None
    self._recipes_manager = recipes_manager.RecipesManager()
    self._recipe = None
    self._state = None

    self._DetermineDataFilesPath()

  def _AddRecipeOptions(self, argument_parser):
    """Adds the recipe options to the argument group.

    Args:
      argument_parser (argparse.ArgumentParser): argparse argument parser.
    """
    subparsers = argument_parser.add_subparsers()

    for recipe in self._recipes_manager.GetRecipes():
      description = '\n'.join(recipe.description)
      subparser = subparsers.add_parser(
          recipe.name, formatter_class=utils.DFTimewolfFormatterClass,
          description=description)
      subparser.set_defaults(recipe=recipe.contents)

      for switch, help_text, default in recipe.args:
        subparser.add_argument(switch, help=help_text, default=default)

      # Override recipe defaults with those specified in Config
      # so that they can in turn be overridden in the commandline
      subparser.set_defaults(**config.Config.get_extra())

  def _DetermineDataFilesPath(self):
    """Determines the data files path."""
    data_files_path = os.path.realpath(__file__)
    data_files_path = os.path.dirname(data_files_path)
    data_files_path = os.path.dirname(data_files_path)
    data_files_path = os.path.dirname(data_files_path)
    data_files_path = os.path.join(data_files_path, 'data')

    if not os.path.isdir(data_files_path):
      data_files_path = self._DEFAULT_DATA_FILES_PATH

    self._data_files_path = data_files_path

  def _GenerateHelpText(self):
    """Generates help text with alphabetically sorted recipes.

    Returns:
      str: help text.
    """
    recipes = self._recipes_manager.GetRecipes()
    if not recipes:
      help_text = '\nNo recipes found.'
    else:
      help_text = '\nAvailable recipes:\n\n'
      for recipe in recipes:
        short_description = recipe.contents.get(
            'short_description', 'No description')
        help_text += ' {0:<35s}{1:s}\n'.format(recipe.name, short_description)

    return help_text

  def LoadConfiguration(self):
    """Loads the configuration."""
    configuration_file_path = os.path.join(self._data_files_path, 'config.json')
    # Try to open config.json and load configuration data from it.
    config.Config.load_extra(configuration_file_path)

    user_directory = os.path.expanduser('~')
    configuration_file_path = os.path.join(user_directory, '.dftimewolfrc')
    config.Config.load_extra(configuration_file_path)

    configuration_file_path = os.path.join('/', 'etc', 'dftimewolf.conf')
    config.Config.load_extra(configuration_file_path)

    configuration_file_path = os.path.join(
        '/', 'usr', 'share', 'dftimewolf', 'dftimewolf.conf')
    config.Config.load_extra(configuration_file_path)

  def ParseArguments(self, arguments):
    """Parses the command line arguments.

    Args:
      arguments (list[str]): command line arguments.

    Returns:
      bool: True if the arguments were successfully parsed.
    """
    help_text = self._GenerateHelpText()

    argument_parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=help_text)

    self._AddRecipeOptions(argument_parser)

    self._command_line_options = argument_parser.parse_args(arguments)
    self._recipe = self._command_line_options.recipe

    self._state = DFTimewolfState(config.Config)
    print('Loading recipe...')
    self._state.load_recipe(self._recipe)

    number_of_modules = len(self._recipe['modules'])
    print('Loaded recipe {0:s} with {1:d} modules'.format(
        self._recipe['name'], number_of_modules))

    return True

  def ReadRecipes(self):
    """Reads the recipe files."""
    if os.path.isdir(self._data_files_path):
      recipes_path = os.path.join(self._data_files_path, 'recipes')
      if os.path.isdir(recipes_path):
        self._recipes_manager.ReadRecipesFromDirectory(recipes_path)

  def RunModules(self):
    """Runs the modules."""
    print('Running modules...')
    self._state.run_modules()
    print('Recipe {0:s} executed successfully.'.format(self._recipe['name']))

  def SetupModules(self):
    """Sets up the modules."""
    # TODO: refactor to only load modules that are used by the recipe.

    print('Setting up modules...')
    self._state.setup_modules(self._command_line_options)
    print('Modules successfully set up!')