diff options
author | Jake Hunsaker <jhunsake@redhat.com> | 2020-09-29 13:03:03 -0400 |
---|---|---|
committer | Jake Hunsaker <jhunsake@redhat.com> | 2020-10-07 13:55:55 -0400 |
commit | 651ffe21f4d3c694bfc9354311519bcde2856808 (patch) | |
tree | 6492c4b30a6130bb8febf336279d399b4010aa3d | |
parent | caa9a2f2a511689080d019ffab61a4de5787d8be (diff) | |
download | sos-651ffe21f4d3c694bfc9354311519bcde2856808.tar.gz |
[cleaner] Add username parser
Adds a username parser for native obfuscation of usernames that appear
in `lastlog` output as collected by the `login` plugin.
Users may also supply additional usernames not appearing in `lastlog`
output via the `--usernames` option for either report, clean, or
collect.
Resolves: #2253
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
-rw-r--r-- | sos/cleaner/__init__.py | 12 | ||||
-rw-r--r-- | sos/cleaner/mappings/username_map.py | 37 | ||||
-rw-r--r-- | sos/cleaner/parsers/username_parser.py | 58 | ||||
-rw-r--r-- | sos/collector/__init__.py | 4 | ||||
-rw-r--r-- | sos/report/__init__.py | 4 |
5 files changed, 113 insertions, 2 deletions
diff --git a/sos/cleaner/__init__.py b/sos/cleaner/__init__.py index e503454e..2d166bb0 100644 --- a/sos/cleaner/__init__.py +++ b/sos/cleaner/__init__.py @@ -26,6 +26,7 @@ from sos.cleaner.parsers.ip_parser import SoSIPParser from sos.cleaner.parsers.mac_parser import SoSMacParser from sos.cleaner.parsers.hostname_parser import SoSHostnameParser from sos.cleaner.parsers.keyword_parser import SoSKeywordParser +from sos.cleaner.parsers.username_parser import SoSUsernameParser from sos.cleaner.obfuscation_archive import SoSObfuscationArchive from sos.utilities import get_human_readable from textwrap import fill @@ -45,7 +46,8 @@ class SoSCleaner(SoSComponent): 'keywords': [], 'map_file': '/etc/sos/cleaner/default_mapping', 'no_update': False, - 'target': '' + 'target': '', + 'usernames': [] } def __init__(self, parser=None, args=None, cmdline=None, in_place=False, @@ -83,7 +85,8 @@ class SoSCleaner(SoSComponent): SoSHostnameParser(self.opts.map_file, self.opts.domains), SoSIPParser(self.opts.map_file), SoSMacParser(self.opts.map_file), - SoSKeywordParser(self.opts.map_file, self.opts.keywords) + SoSKeywordParser(self.opts.map_file, self.opts.keywords), + SoSUsernameParser(self.opts.map_file, self.opts.usernames) ] self.log_info("Cleaner initialized. From cmdline: %s" @@ -175,6 +178,9 @@ third party. action='store_true', help='Do not update the --map file with new ' 'mappings from this run') + clean_grp.add_argument('--usernames', dest='usernames', default=[], + action='extend', + help='List of usernames to obfuscate') def set_target_path(self, path): """For use by report and collect to set the TARGET option appropriately @@ -551,6 +557,8 @@ third party. with open(prep_file, 'r') as host_file: hostname = host_file.readline().strip() parser.load_hostname_into_map(hostname) + if isinstance(parser, SoSUsernameParser): + parser.load_usernames_into_map(prep_file) self.obfuscate_file(prep_file, parser.prep_map_file, archive.archive_name) diff --git a/sos/cleaner/mappings/username_map.py b/sos/cleaner/mappings/username_map.py new file mode 100644 index 00000000..cdbf36fe --- /dev/null +++ b/sos/cleaner/mappings/username_map.py @@ -0,0 +1,37 @@ +# Copyright 2020 Red Hat, Inc. Jake Hunsaker <jhunsake@redhat.com> + +# This file is part of the sos project: https://github.com/sosreport/sos +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# version 2 of the GNU General Public License. +# +# See the LICENSE file in the source distribution for further information. + +from sos.cleaner.mappings import SoSMap + + +class SoSUsernameMap(SoSMap): + """Mapping to store usernames matched from ``lastlog`` output. + + Usernames are obfuscated as ``obfuscateduserX`` where ``X`` is a counter + that gets incremented for every new username found. + + Note that this specifically obfuscates user_names_ and not UIDs. + """ + + name_count = 0 + + def load_names_from_options(self, opt_names): + for name in opt_names: + if name not in self.dataset.keys(): + self.add(name) + + def sanitize_item(self, username): + """Obfuscate a new username not currently found in the map + """ + ob_name = "obfuscateduser%s" % self.name_count + self.name_count += 1 + if ob_name in self.dataset.values(): + return self.sanitize_item(username) + return ob_name diff --git a/sos/cleaner/parsers/username_parser.py b/sos/cleaner/parsers/username_parser.py new file mode 100644 index 00000000..af21db34 --- /dev/null +++ b/sos/cleaner/parsers/username_parser.py @@ -0,0 +1,58 @@ +# Copyright 2020 Red Hat, Inc. Jake Hunsaker <jhunsake@redhat.com> + +# This file is part of the sos project: https://github.com/sosreport/sos +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# version 2 of the GNU General Public License. +# +# See the LICENSE file in the source distribution for further information. + + +from sos.cleaner.parsers import SoSCleanerParser +from sos.cleaner.mappings.username_map import SoSUsernameMap + + +class SoSUsernameParser(SoSCleanerParser): + """Parser for obfuscating usernames within an sosreport archive. + + Note that this parser does not rely on regex matching directly, like most + other parsers do. Instead, usernames are discovered via scraping the + collected output of lastlog. As such, we do not discover new usernames + later on, and only usernames present in lastlog output will be obfuscated, + and those passed via the --usernames option if one is provided. + """ + + name = 'Username Parser' + map_file_key = 'username_map' + prep_map_file = 'sos_commands/login/lastlog_-u_1000-60000' + regex_patterns = [] + skip_list = [ + 'nobody', + 'nfsnobody', + 'root' + ] + + def __init__(self, conf_file=None, opt_names=None): + self.mapping = SoSUsernameMap() + super(SoSUsernameParser, self).__init__(conf_file) + self.mapping.load_names_from_options(opt_names) + + def load_usernames_into_map(self, fname): + """Since we don't get the list of usernames from a straight regex for + this parser, we need to override the initial parser prepping here. + """ + with open(fname, 'r') as lastfile: + for line in lastfile.read().splitlines()[1:]: + user = line.split()[0] + if user in self.skip_list: + continue + self.mapping.get(user) + + def parse_line(self, line): + count = 0 + for username in self.mapping.dataset.keys(): + if username in line: + count = line.count(username) + line = line.replace(username, self.mapping.get(username)) + return line, count diff --git a/sos/collector/__init__.py b/sos/collector/__init__.py index ce52198e..3390e0b0 100644 --- a/sos/collector/__init__.py +++ b/sos/collector/__init__.py @@ -91,6 +91,7 @@ class SoSCollector(SoSComponent): 'ssh_user': 'root', 'timeout': 600, 'verify': False, + 'usernames': [], 'upload': False, 'upload_url': None, 'upload_directory': None, @@ -373,6 +374,9 @@ class SoSCollector(SoSComponent): default='/etc/sos/cleaner/default_mapping', help=('Provide a previously generated mapping' ' file for obfuscation')) + cleaner_grp.add_argument('--usernames', dest='usernames', default=[], + action='extend', + help='List of usernames to obfuscate') def _check_for_control_persist(self): """Checks to see if the local system supported SSH ControlPersist. diff --git a/sos/report/__init__.py b/sos/report/__init__.py index 9b2555ed..a938f706 100644 --- a/sos/report/__init__.py +++ b/sos/report/__init__.py @@ -107,6 +107,7 @@ class SoSReport(SoSComponent): 'since': None, 'verify': False, 'allow_system_changes': False, + 'usernames': [], 'upload': False, 'upload_url': None, 'upload_directory': None, @@ -305,6 +306,9 @@ class SoSReport(SoSComponent): default='/etc/sos/cleaner/default_mapping', help=('Provide a previously generated mapping' ' file for obfuscation')) + cleaner_grp.add_argument('--usernames', dest='usernames', default=[], + action='extend', + help='List of usernames to obfuscate') def print_header(self): print("\n%s\n" % _("sosreport (version %s)" % (__version__,))) |