From a4ea50426184d30cbe849a8f80bfd5c975075c9e Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sat, 29 Feb 2020 11:33:14 -0800 Subject: [PATCH] add /etc/passwd parser --- docgen.sh | 1 + docs/parsers/passwd.md | 126 +++++++++++++++++++++++++++++ jc/cli.py | 1 + jc/parsers/passwd.py | 175 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 303 insertions(+) create mode 100644 docs/parsers/passwd.md create mode 100644 jc/parsers/passwd.py diff --git a/docgen.sh b/docgen.sh index 3ec9bafe..4c9059c1 100755 --- a/docgen.sh +++ b/docgen.sh @@ -28,6 +28,7 @@ pydocmd simple jc.parsers.lsmod+ > ../docs/parsers/lsmod.md pydocmd simple jc.parsers.lsof+ > ../docs/parsers/lsof.md pydocmd simple jc.parsers.mount+ > ../docs/parsers/mount.md pydocmd simple jc.parsers.netstat+ > ../docs/parsers/netstat.md +pydocmd simple jc.parsers.passwd+ > ../docs/parsers/passwd.md pydocmd simple jc.parsers.pip_list+ > ../docs/parsers/pip_list.md pydocmd simple jc.parsers.pip_show+ > ../docs/parsers/pip_show.md pydocmd simple jc.parsers.ps+ > ../docs/parsers/ps.md diff --git a/docs/parsers/passwd.md b/docs/parsers/passwd.md new file mode 100644 index 00000000..002954c6 --- /dev/null +++ b/docs/parsers/passwd.md @@ -0,0 +1,126 @@ +# jc.parsers.passwd +jc - JSON CLI output utility /etc/passwd fuke Parser + +Usage: + + specify --passwd as the first argument if the piped input is coming from /etc/passwd + +Compatibility: + + 'linux', 'darwin', 'aix', 'freebsd' + +Examples: + + $ cat /etc/passwd | jc --passwd -p + [ + { + "username": "nobody", + "password": "*", + "uid": -2, + "gid": -2, + "comment": "Unprivileged User", + "home": "/var/empty", + "shell": "/usr/bin/false" + }, + { + "username": "root", + "password": "*", + "uid": 0, + "gid": 0, + "comment": "System Administrator", + "home": "/var/root", + "shell": "/bin/sh" + }, + { + "username": "daemon", + "password": "*", + "uid": 1, + "gid": 1, + "comment": "System Services", + "home": "/var/root", + "shell": "/usr/bin/false" + }, + ... + ] + + $ cat /etc/passwd | jc --passwd -p -r + [ + { + "username": "nobody", + "password": "*", + "uid": "-2", + "gid": "-2", + "comment": "Unprivileged User", + "home": "/var/empty", + "shell": "/usr/bin/false" + }, + { + "username": "root", + "password": "*", + "uid": "0", + "gid": "0", + "comment": "System Administrator", + "home": "/var/root", + "shell": "/bin/sh" + }, + { + "username": "daemon", + "password": "*", + "uid": "1", + "gid": "1", + "comment": "System Services", + "home": "/var/root", + "shell": "/usr/bin/false" + }, + ... + ] + +## info +```python +info(self, /, *args, **kwargs) +``` + +## process +```python +process(proc_data) +``` + +Final processing to conform to the schema. + +Parameters: + + proc_data: (dictionary) raw structured data to process + +Returns: + + List of dictionaries. Structured data with the following schema: + + [ + { + "username": string, + "password": string, + "uid": integer, + "gid": integer, + "comment": string, + "home": string, + "shell": string + } + ] + +## parse +```python +parse(data, raw=False, quiet=False) +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of dictionaries. Raw or processed structured data. + diff --git a/jc/cli.py b/jc/cli.py index 8a2a2280..384a4c89 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -46,6 +46,7 @@ parsers = [ 'lsof', 'mount', 'netstat', + 'passwd', 'pip-list', 'pip-show', 'ps', diff --git a/jc/parsers/passwd.py b/jc/parsers/passwd.py new file mode 100644 index 00000000..62854650 --- /dev/null +++ b/jc/parsers/passwd.py @@ -0,0 +1,175 @@ +"""jc - JSON CLI output utility /etc/passwd fuke Parser + +Usage: + + specify --passwd as the first argument if the piped input is coming from /etc/passwd + +Compatibility: + + 'linux', 'darwin', 'aix', 'freebsd' + +Examples: + + $ cat /etc/passwd | jc --passwd -p + [ + { + "username": "nobody", + "password": "*", + "uid": -2, + "gid": -2, + "comment": "Unprivileged User", + "home": "/var/empty", + "shell": "/usr/bin/false" + }, + { + "username": "root", + "password": "*", + "uid": 0, + "gid": 0, + "comment": "System Administrator", + "home": "/var/root", + "shell": "/bin/sh" + }, + { + "username": "daemon", + "password": "*", + "uid": 1, + "gid": 1, + "comment": "System Services", + "home": "/var/root", + "shell": "/usr/bin/false" + }, + ... + ] + + $ cat /etc/passwd | jc --passwd -p -r + [ + { + "username": "nobody", + "password": "*", + "uid": "-2", + "gid": "-2", + "comment": "Unprivileged User", + "home": "/var/empty", + "shell": "/usr/bin/false" + }, + { + "username": "root", + "password": "*", + "uid": "0", + "gid": "0", + "comment": "System Administrator", + "home": "/var/root", + "shell": "/bin/sh" + }, + { + "username": "daemon", + "password": "*", + "uid": "1", + "gid": "1", + "comment": "System Services", + "home": "/var/root", + "shell": "/usr/bin/false" + }, + ... + ] +""" +import jc.utils + + +class info(): + version = '1.0' + description = '/etc/passwd file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + # details = 'enter any other details here' + + # compatible options: linux, darwin, cygwin, win32, aix, freebsd + compatible = ['linux', 'darwin', 'aix', 'freebsd'] + + +__version__ = info.version + + +def process(proc_data): + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (dictionary) raw structured data to process + + Returns: + + List of dictionaries. Structured data with the following schema: + + [ + { + "username": string, + "password": string, + "uid": integer, + "gid": integer, + "comment": string, + "home": string, + "shell": string + } + ] + """ + for entry in proc_data: + int_list = ['uid', 'gid'] + for key in int_list: + if key in entry: + try: + key_int = int(entry[key]) + entry[key] = key_int + except (ValueError): + entry[key] = None + + return proc_data + + +def parse(data, raw=False, quiet=False): + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) output preprocessed JSON if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of dictionaries. Raw or processed structured data. + """ + if not quiet: + jc.utils.compatibility(__name__, info.compatible) + + raw_output = [] + cleandata = data.splitlines() + + # Clear any blank lines + cleandata = list(filter(None, cleandata)) + + if cleandata: + for entry in cleandata: + if entry.startswith('#'): + continue + + output_line = {} + fields = entry.split(':') + + output_line['username'] = fields[0] + output_line['password'] = fields[1] + output_line['uid'] = fields[2] + output_line['gid'] = fields[3] + output_line['comment'] = fields[4] + output_line['home'] = fields[5] + output_line['shell'] = fields[6] + + raw_output.append(output_line) + + if raw: + return raw_output + else: + return process(raw_output)