aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sos/cleaner/__init__.py12
-rw-r--r--sos/cleaner/mappings/username_map.py37
-rw-r--r--sos/cleaner/parsers/username_parser.py58
-rw-r--r--sos/collector/__init__.py4
-rw-r--r--sos/report/__init__.py4
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__,)))