This file is indexed.

/usr/lib/python2.7/dist-packages/rekall/config.py is in python-rekall-core 1.6.0+dfsg-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
#!/usr/bin/python

# Rekall
# Copyright (C) 2012 Michael Cohen <scudette@gmail.com>
# Copyright 2013 Google Inc. All Rights Reserved.
#
# 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; either version 2 of the License, or (at
# your option) any later version.
#
# 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
#

"""This is the Rekall configuration system.

Rekall maintains a persistent file with global settings in the user's home
directory. This makes it easy for users to retain commonly used Rekall
parameters.

Note that the configuration file is only used in interactive mode. When used as
a library the configuration file has no effect.
"""

__author__ = "Michael Cohen <scudette@gmail.com>"

import collections
import logging
import os
import sys
import tempfile
import yaml

from rekall import constants


class CommandMetadata(object):
    """A class that carried a plugin's configuration.

    A plugin is responsible for declaring its metadata by calling this
    configuration object's methods from the args() class method.

    There are two things that plugin must declare:

    add_*_arg(): Calling these functions declares an argument for this
       plugin. See the documentation for that method for details.

    add_metadata(): This method provides additional metadata about this plugin.
    """

    def __init__(self, plugin_cls=None):
        self.args = collections.OrderedDict()
        self.requirements = set()
        self.plugin_cls = plugin_cls
        if plugin_cls:
            plugin_cls.args(self)

        self.description = (plugin_cls.__doc__ or
                            plugin_cls.__init__.__doc__ or "")

    def set_description(self, description):
        self.description = description

    def add_positional_arg(self, name, type="string"):
        """Declare a positional arg."""
        self.args[name] = dict(type=type)

    def add_argument(self, short_opt, long_opt=None, **options):
        """Add a new argument to the command.

        This method is used in the args() class method to add a new command line
        arg to the plugin. It is similar to the argparse add_argument() method
        but it adds a type parameter which conveys higher level information
        about the argument. Currently supported types:

        - ArrayIntParser: A list of integers (possibly encoded as hex strings).
        - ArrayStringParser: A list of strings.
        - Float: A float.
        - IntParser: An integer (possibly encoded as a hex string).
        - Boolean: A flag - true/false.
        - ChoiceArray: A comma separated list of strings which must be from the
            choices parameter.
        """
        if "action" in options:
            raise RuntimeError("Action keyword is deprecated.")

        if not isinstance(options.get("type", ""), str):
            raise RuntimeError("Type must be a string.")

        # Is this a positional arg?
        positional = options.pop("positional", False)

        # For now we support option names with leading --.
        if long_opt is None:
            long_opt = short_opt
            short_opt = ""

        if long_opt.startswith("-"):
            long_opt = long_opt.lstrip("-")
            short_opt = short_opt.lstrip("-")
            positional = False

        name = long_opt
        options["short_opt"] = short_opt
        options["positional"] = positional
        options["name"] = name

        self.args[name] = options

    def add_requirement(self, requirement):
        """Add a requirement for this plugin.

        Currently supported requirements:
         - profile: A profile must exist for this plugin to run.

         - physical_address_space: A Physical Address Space (i.e. an image file)
           must exist for this plugin to work.
        """
        self.requirements.add(requirement)

    def Metadata(self):
        return dict(requirements=list(self.requirements),
                    arguments=self.args.values(), name=self.plugin_cls.name,
                    description=self.description)

    def ApplyDefaults(self, args):
        """Update args with the defaults.

        If an option in args is None, we update it with the default value for
        this option.
        """
        for name, options in self.args.iteritems():
            if options.get("dest") == "SUPPRESS":
                continue

            name = name.replace("-", "_")
            try:
                if args[name] is None:
                    args[name] = options.get("default")
            except KeyError:
                pass

        return args


def GetHomeDir(session):
    return (
        session.GetParameter("home", cached=False) or
        os.environ.get("HOME") or      # Unix
        os.environ.get("USERPROFILE") or # Windows
        tempfile.gettempdir() or  # Fallback tmp dir.
        ".")


# This is the configuration file template which will be created if the user does
# not have an existing file. The aim is not to exhaustively list all possible
# options, rather to ensure that reasonable defaults are specified initially.
DEFAULT_CONFIGURATION = dict(
    repository_path=constants.PROFILE_REPOSITORIES,

    # This is the path of the cache directory - given relative to the config
    # file (or it can be specified as an absolute path).
    cache_dir=".rekall_cache",
    )

# Global options control the framework's own flags. They are not associated with
# any one plugin.
OPTIONS = CommandMetadata()


def GetConfigFile(session):
    """Gets the configuration stored in the config file.

    Searches for the config file in reasonable locations.

    Return:
      configuration stored in the config file. If the file is not found, returns
      an empty configuration.
    """
    search_path = [
        # Next to the main binary (in case of pyinstaller - rekall.exe).
        os.path.join(os.path.dirname(sys.executable), ".rekallrc"),
        ".rekallrc",   # Current directory.
        os.path.join(GetHomeDir(session), ".rekallrc"), # Home directory overrides system.
        "/etc/rekallrc",
    ]

    for path in search_path:
        try:
            with open(path, "rb") as fd:
                result = yaml.safe_load(fd)
                logging.debug("Loaded configuration from %s", path)

                # Allow the config file to update the
                # environment. This is handy in standalone deployment
                # where one can update %HOME% and ensure Rekall does
                # not touch the drive.
                os.environ.update(result.get("environment", {}))

                return result

        except (IOError, ValueError):
            pass

    return {}


def CreateDefaultConfigFile(session):
    """Creates a default config file."""
    homedir = GetHomeDir(session)
    if homedir:
        try:
            filename = "%s/.rekallrc" % homedir
            with open(filename, "wb") as fd:
                yaml.dump(DEFAULT_CONFIGURATION, fd)

            logging.info("Created new configuration file %s", filename)
            cache_dir = os.path.join(
                homedir, DEFAULT_CONFIGURATION["cache_dir"])

            os.makedirs(cache_dir)
            logging.info("Created new cache directory %s", cache_dir)

            return DEFAULT_CONFIGURATION
        except (IOError, OSError):
            pass

    # Can not write it anywhere but at least we start with something sensible.
    return DEFAULT_CONFIGURATION


def MergeConfigOptions(state, session):
    """Read the config file and apply the config options to the session."""
    config_data = GetConfigFile(session)
    # An empty configuration file - we try to initialize a new one.
    if not config_data:
        config_data = CreateDefaultConfigFile(session)

    # First apply the defaults:
    for name, options in OPTIONS.args.iteritems():
        if name not in config_data:
            config_data[name] = options.get("default")

    for k, v in config_data.items():
        state.Set(k, v)


def RemoveGlobalOptions(state):
    """Remove all global options from state dictionary."""
    state.pop("SUPPRESS", None)

    for name in OPTIONS.args:
        state.pop(name, None)

    return state


def DeclareOption(*args, **kwargs):
    """Declare a config option for command line and config file."""
    # Options can not be positional!
    kwargs["positional"] = False
    default = kwargs.get("default")
    if default is not None and isinstance(default, str):
        kwargs["default"] = unicode(default)

    OPTIONS.add_argument(*args, **kwargs)