- smbd - number of logins, list users & clients
- sshd (DEPRECATED) - logins by user/hostname, attempted root logins, invalid users
- sshd-journald - logins by user/hostname, attempted root logins, invalid users (requires libsystemd)
-- sudo - number of sessions, list users and commands
+- sudo (DEPRECATED)- number of sessions, list users and commands
+- sudo-journald - number of sessions, list users and commands (requires libsystemd)
- sysinfo - hostname, OS, OS version, platform, processors
+- systemctl - system status, running/failed units (requires libsystemd)
- temperature - instantaneous temperatures of motherboard, CPU, cores, disks
+- ufw - blocked packets, port and IP data (requires libsystemd)
- zfs - zpool scrub reports, disk usage
.. _configuration:
mailbin
Path to the MTA binary (usually Postfix). Default: /usr/bin/mail
+======================
+Default parser options
+======================
+
+Each parser has its own set of options in a section with the name of the parser. In the case of multiple versions of the same parser (e.g. sshd and sshd-journald), the configuration section goes by the base name (e.g. sshd). Options defined in individual parser sections override those defined in the global configuration.
+
+####
+cron
+####
+
+period
+ Maximum age of logs to analyse. Overrides global config. Only used in cron-journald at the moment. See :ref:`period` for more information. Default: empty
+
+.. _period:
+
+####
+sshd
+####
+
+period
+ Maximum age of logs to analyse. Overrides global config. Only used in sshd-journald at the moment. See :ref:`period` for more information. Default: empty
+sshd-resolve-domains
+ DNS lookup configuration for sshd parsers only (overrides global config). Accepted values are `ip`, `fqdn`, `fqdn-implicit`, and `host-only`. See the global setting `resolve-domains` for more information. Default: empty
+
+####
+smbd
+####
+
+shares
+ Regular expression string for which Samba shares to include when parsing logs. To consider all shares, set this to `.*`. To exclude a certain share, use negative lookaround. Default: `^((?!IPC\$).)*$`
+users
+ Regular expression string for which user@hostname values to include when parsing logs. This could be used to exclude logins from a trusted user or hostname. Default: `.*`
+smbd-resolve-domains
+ DNS lookup configuration for smbd parsers only (overrides global config). Accepted values are `ip`, `fqdn`, `fqdn-implicit`, and `host-only`. See the global setting `resolve-domains` for more information. Default: empty
+period
+ Maximum age of logs to analyse. Overrides global config. Only used in smbd-journald at the moment. See :ref:`period` for more information. Default: empty
+
+#####
+httpd
+#####
+
+httpd-resolve-domains
+ DNS lookup configuration for httpd parser only (overrides global config). Accepted values are `ip`, `fqdn`, `fqdn-implicit`, and `host-only`. See the global setting `resolve-domains` for more information. Default: empty
+period
+ Maximum age of logs to analyse. Overrides global config. See :ref:`period` for more information. Default: empty
+
+###
+ufw
+###
+
+ufw-resolve-domains
+ DNS lookup configuration for ufw parser only (overrides global config). Accepted values are `ip`, `fqdn`, `fqdn-implicit`, and `host-only`. See the global setting `resolve-domains` for more information. Default: empty
+period
+ Maximum age of logs to analyse. Overrides global config. See :ref:`period` for more information. Default: empty
+
+####
+sudo
+####
+
+period
+ Maximum age of logs to analyse. Overrides global config. See :ref:`period` for more information. Default: empty
+
+#########
+systemctl
+#########
+
+period
+ Maximum age of logs to analyse. Overrides global config. See :ref:`period` for more information. Default: empty
+show-all
+ Whether to include services which are running but okay in the output. Default: true
+
+
+
+========================
+Log period configuration
+========================
+
+Some parsers support custom time periods to be searched for logs. This period is specified as a string in the configuration section of supported parsers, and is a timespan relative to the time when the parser is initialised. The time parsing functionality uses a modified version of `timeparse.py` originally written by Will Roberts under the MIT License. The following excerpt is taken from the documentation of `timeparse.py`:
+
+.. autofunction:: logparse.timeparse.strseconds
+
.. _variables:
=====================
"""
This file contains global functions for formatting and printing data. This file
-should be imported into individual log-parsing scripts located in logs/*. Data
-is formatted in HTML or plaintext. Writing to disk and/or emailng data is left
-to interface.py.
+should be imported into individual log-parsing scripts located in the default
+logparse.parsers module or in the user-supplied parsers directory. Data is
+formatted in HTML or plaintext. Writing to disk and/or emailng data is left to
+interface.py.
"""
import os
This should be run by interface.py after every instance of parse_log().
"""
+ if section == None:
+ logger.warning("Received null section")
+ return
self.append(PlaintextBox(
content=section.title, double=False,
fullwidth=False, vpadding=0, hpadding=" ").draw())
instance of parse_log().
"""
+ if section == None:
+ logger.warning("Received null section")
+ return
self.append(opentag('div', 1, section.title, 'section'))
self.append(self._gen_title(section.title))
if section.period and section.period.unique:
--- /dev/null
+#
+# sudo-journald.py
+#
+# Get number of sudo sessions for each user
+#
+
+import re
+from systemd import journal
+
+from logparse.formatting import *
+from logparse.util import readlog
+from logparse.config import prefs
+from logparse.load_parsers import Parser
+
+class SudoCommand():
+
+ def __init__(self, msg):
+ self.init_user, self.pwd, self.su, self.command = re.search(
+ r"\s*(?P<init_user>\w*) : TTY=.* ; PWD=(?P<pwd>\S*) ;"
+ " USER=(?P<su>\w*) ; COMMAND=(?P<command>\S*)", msg)\
+ .groupdict().values()
+
+class Sudo(Parser):
+
+ def __init__(self):
+ super().__init__()
+ self.name = "sudo"
+ self.info = "Get number of sudo sessions for each user"
+
+ def parse_log(self):
+
+ logger.debug("Starting sudo section")
+ section = Section("sudo")
+
+ if not (config.prefs.getboolean("sudo", "summary")
+ or config.prefs.getboolean("sudo", "list-users")):
+ logger.warning("Both summary and list-users configuration options "
+ "are set to false, so no output will be generated. "
+ "Skipping this parser.")
+ return None
+
+ j = journal.Reader()
+ j.this_machine()
+ j.log_level(journal.LOG_INFO)
+ j.add_match(_COMM="sudo")
+ j.seek_realtime(section.period.startdate)
+ j.log_level(5)
+
+ logger.debug("Searching for sudo commands")
+
+ messages = [entry["MESSAGE"] for entry in j if "MESSAGE" in entry]
+
+ commands_objects = [] # list of command objects
+ init_users = {} # keys are users, values are lists of commands
+
+ logger.debug("Parsing sudo log messages")
+
+ for msg in messages:
+
+ if "COMMAND=" in msg:
+ try:
+ command_obj = SudoCommand(msg)
+ except Exception as e:
+ logger.warning("Malformed sudo log message: {0}. "
+ "Error message: {1}".format(msg, str(e)))
+ continue
+ if config.prefs.getboolean("sudo", "truncate-commands"):
+ command_obj.command = command_obj.command.split("/")[-1]
+ commands_objects.append(command_obj)
+ if not command_obj.init_user in init_users:
+ init_users[command_obj.init_user] = []
+ init_users[command_obj.init_user].append(
+ command_obj.su + ": " + command_obj.command)
+
+ logger.debug("Generating output")
+
+ if len(commands_objects) == 0:
+ logger.warning("No sudo commands found")
+ return
+
+ if config.prefs.getboolean("sudo", "summary"):
+
+ summary_data = Data()
+ summary_data.subtitle = plural("sudo session", len(commands_objects))
+
+ if all(cmd.su == commands_objects[0].su for cmd in commands_objects):
+ # Only one superuser
+ if len(set(cmd.init_user for cmd in commands_objects)) > 1:
+ # Multiple initiating users
+ summary_data.subtitle += " for superuser " \
+ + commands_objects[0].su
+ summary_data.items = ["{}: {}".format(cmd.init_user, cmd.command)
+ for cmd in commands_objects]
+ else:
+ # Only one initiating user
+ summary_data.subtitle += " opened by " \
+ + commands_objects[0].init_user + " for " \
+ + commands_objects[0].su
+ summary_data.items = [cmd.command
+ for cmd in commands_objects]
+ else:
+ # Multiple superusers
+ if len(set(cmd.init_user for cmd in commands_objects)) > 1:
+ # Multiple initiating users
+ summary_data.subtitle += " for " + plural("superuser",
+ len(set(cmd.su for cmd in commands_objects)))
+ summary_data.items = ["{}→{}: {}".format(
+ cmd.init_user, cmd.su, cmd.command)
+ for cmd in commands_objects]
+ else:
+ # Only one initiating user
+ summary_data.subtitle += " by " \
+ + commands_objects[0].init_user \
+ + " for " + plural("superuser",
+ len(set(cmd.su
+ for cmd in commands_objects)))
+ summary_data.items = ["{}: {}".format(
+ cmd.su, cmd.command) for cmd in commands_objects]
+ summary_data.orderbyfreq()
+ summary_data.truncl(config.prefs.getint("logparse", "maxcmd"))
+ section.append_data(summary_data)
+
+ if config.prefs.getboolean("sudo", "list-users") \
+ and len(set(cmd.init_user for cmd in commands_objects)) > 1:
+ for user, user_commands in init_users.items():
+ user_data = Data()
+ user_data.subtitle = plural("sudo session",
+ len(user_commands)) + " for user " + user
+ user_data.items = user_commands
+ user_data.orderbyfreq()
+ user_data.truncl(config.prefs.getint("logparse", "maxcmd"))
+ section.append_data(user_data)
+
+ logger.info("Finished sudo section")
+
+ return section