This file is indexed.

/usr/lib/python3/dist-packages/requestbuilder/config.py is in python3-requestbuilder 0.5.2-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
# Copyright (c) 2012-2016 Hewlett Packard Enterprise Development LP
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

from __future__ import absolute_import

import itertools
import logging


import six
from six.moves import configparser


class ConfigView(object):
    def __init__(self, data, region=None, user=None):
        self.log = data.log
        self.__data = data
        self.__region = None
        self.__user = None
        if region:
            self.region = region
        if user:
            self.user = user

    @property
    def region(self):
        return self.__region

    @region.setter
    def region(self, value):
        self.__region = value
        self.log.info('set region to %s', value)

    @property
    def user(self):
        return self.__user

    @user.setter
    def user(self, value):
        self.__user = value
        self.log.info('set user to %s', value)

    def clone(self, region=None, user=None):
        region = region or self.region
        user = user or self.user
        return ConfigView(self.__data, region=region, user=user)

    def get_global_option(self, option, redact=False):
        return self.__data.lookup_global(option, redact=redact)

    def get_region_option(self, option, region=None, redact=False):
        return self.get_region_option2(option, region=region,
                                       redact=redact)[0]

    def get_region_option2(self, option, region=None, redact=False):
        region = region or self.region
        if region:
            return self.__data.lookup(self.__data.regions, region, option,
                                      redact=redact,
                                      confdict_log_name='region')
        return None, None

    def get_user_option(self, option, user=None, redact=False):
        return self.get_user_option2(option, user=user, redact=redact)[0]

    def get_user_option2(self, option, user=None, redact=False):
        user = user or self.user
        if user:
            return self.__data.lookup(self.__data.users, user, option,
                                      redact=redact, confdict_log_name='user')
        return None, None

    def get_all_region_options(self, option):
        return self.__get_all_options(self.__data.regions, option)

    def get_all_user_options(self, option):
        return self.__get_all_options(self.__data.users, option)

    @staticmethod
    def __get_all_options(confdict, option):
        matches = {}
        for section, options in six.iteritems(confdict):
            if '*' not in section and option in options:
                matches[section] = options[option]
        return matches

    @staticmethod
    def convert_to_bool(value, default=None):
        if value is None:
            return default
        elif str(value).lower() in ('true', '1', 'yes', 'on'):
            return True
        elif str(value).lower() in ('false', '0', 'no', 'off'):
            return False
        else:
            raise ValueError('value {0} is not boolean'.format(repr(value)))


class ConfigData(object):
    def __init__(self, filenames):
        self.log = logging.getLogger('Config')
        self.log.addHandler(_NullLogHandler())  # cheap warning silencing
        self.globals = {}
        self.regions = {}
        self.users = {}
        self._memo = {}
        self._parse_config(filenames)

    def _parse_config(self, filenames):
        parser = configparser.SafeConfigParser()
        parser.read(filenames)
        for section in parser.sections():
            if section == 'global':
                self.globals = dict(parser.items(section))
            elif section.startswith('region '):
                region = section.split()[1]
                if any(chunk == '' for chunk in region.split(':')):
                    raise ValueError(
                        'configuration file region {0} must not contain '
                        'an empty namespace'.format(repr(region)))
                if '@' in region:
                    raise ValueError(
                        'configuration file region {0} must not contain '
                        '@ characters'.format(repr(region)))
                self.regions[region] = dict(parser.items(section))
                self.regions[region].setdefault('name', region.rsplit(':')[-1])
            elif section.startswith('user '):
                user = section.split()[1]
                if any(chunk == '' for chunk in user.split(':')):
                    raise ValueError(
                        'configuration file user {0} must not contain '
                        'an empty namespace'.format(repr(user)))
                if '@' in user:
                    raise ValueError(
                        'configuration file user {0} must not contain '
                        '@ characters'.format(repr(user)))
                self.users[user] = dict(parser.items(section))
            # Ignore unrecognized sections for forward compatibility

    def lookup_global(self, option, redact=False):
        self._memo.setdefault(id(self.globals), {})
        if option in self._memo[id(self.globals)]:
            return self._memo[id(self.globals)][option]
        else:
            self.log.info('finding global option %s', option)
            value = self.globals.get(option)
            self._memo[id(self.globals)][option] = value
            if value and redact:
                self.log.info('  found   %s = <redacted>', option)
            elif value:
                self.log.info('  found   %s = %s', option, value)
            else:
                self.log.info('  novalue for %s', option)
            return value

    def lookup(self, confdict, section, option, redact=False, seen=None,
               confdict_log_name=None):
        self._memo.setdefault(id(confdict), {})
        if (section, option) in self._memo[id(confdict)]:
            return self._memo[id(confdict)][(section, option)]
        else:
            if confdict_log_name is not None:
                self.log.info('finding %s option %s', confdict_log_name,
                              option)
            values = self.__lookup(confdict, section, option, redact=redact,
                                   seen=seen)
            self._memo[id(confdict)][(section, option)] = values
            return values

    def __lookup(self, confdict, section, option, redact=False, seen=None):
        def redact_if_necessary(value):
            if redact:
                return '<redacted>'
            else:
                return value

        if seen is None:
            seen = []

        # Try wildcard combinations, from most specific to least specific,
        # except for the '*' section, which we handle later on because it is
        # also the global default.
        section_bits = section.split(':')
        for prd in itertools.product((True, False), repeat=len(section_bits)):
            if prd == (False,):
                continue  # We'll handle '*' later.
            s_section = ':'.join(section_bits[i] if prd[i] else '*'
                                 for i in range(len(section_bits)))
            self.log.debug('  section %s', s_section)
            if s_section in confdict and option in confdict[s_section]:
                value = confdict[s_section][option]
                # Check if we're redirected to another section.
                if value.startswith('use '):
                    value_bits = value.split()
                    if len(value_bits) == 1:
                        raise ValueError("something must follow 'use' in {0}"
                                         .format(value))
                    new_section = value_bits[1]
                    if len(value_bits) > 2:
                        new_option = value_bits[2]
                    else:
                        new_option = option
                    self.log.debug('  jump-to %s::%s (deferred)', new_section,
                                   new_option)
                    if new_section not in seen:
                        return self.lookup(confdict, new_section, new_option,
                                           redact=redact,
                                           seen=(seen + [section]))
                    else:
                        self.log.warning('  aborting jump due to a loop')
                # We're done!
                self.log.info('  found   %s::%s = %s', s_section, option,
                              redact_if_necessary(repr(value)))
                return value, s_section
        # Then see if we can find an exact match with a prefix in front of it.
        # Example:  'us-east-1' -> 'aws:us-east-1'
        prefixed_counts = {}
        for s_section in confdict:
            s_section_bits = s_section.split(':')
            if (len(s_section_bits) > len(section_bits) and
                    s_section_bits[-len(section_bits):] == section_bits):
                # It is longer and its last bits are the same as the entirety
                # of section_bits
                prefixed_counts.setdefault(len(s_section_bits), [])
                prefixed_counts[len(s_section_bits)].append(s_section)
        if prefixed_counts:
            shortest_prefixed = prefixed_counts[min(prefixed_counts)]
            if len(shortest_prefixed) == 1:
                self.log.debug('  jump-to %s::%s (from %s)',
                               shortest_prefixed[0], option, section)
                if shortest_prefixed[0] not in seen:
                    return self.lookup(confdict, shortest_prefixed[0], option,
                                       redact=redact, seen=(seen + [section]))
                else:
                    self.log.warning('  aborting jump due to a loop')
            else:
                raise ValueError(
                    '{0} is ambiguous; closest matches are {1}'.format(
                        repr(section), ', '.join(shortest_prefixed)))
        # Finally, try the global default, '*'.
        self.log.debug('  section *')
        if '*' in confdict and option in confdict['*']:
            self.log.info('  found   *::%s = %s', option,
                          redact_if_necessary(repr(value)))
            return value, '*'
        self.log.info('  novalue for %s', option)
        return None, None


class _NullLogHandler(logging.Handler):
    def handle(self, record):
        pass

    def emit(self, record):
        pass

    def createLock(self):
        self.lock = None