""" Find number of ssh logins and authorised users (uses /var/log/auth.log) NOTE: This file is now deprecated in favour of the newer journald mechanism used in sshd-journald.py. This parser is still functional but is slower and has less features. Please switch over if possible. """ import re from logparse.formatting import * from logparse.util import readlog, resolve from logparse import config from logparse.load_parsers import Parser class Sshd(Parser): def __init__(self): super().__init__() self.name = "sshd" self.info = "Find number of ssh logins and authorised users " "(uses /var/log/auth.log)" self.deprecated = True self.successor = "sshd_journald" def parse_log(self): logger.warning("NOTE: This sshd parser is now deprecated. " "Please use sshd-journald if possible.") logger.debug("Starting sshd section") section = Section("ssh") logger.debug("Searching for matches in {0}".format( config.prefs.get("logs", "auth"))) authlog = readlog(config.prefs.get("logs", "auth")) matches = re.findall('.*sshd.*Accepted publickey for .* from .*', authlog) # get all logins invalid_matches = re.findall(".*sshd.*Invalid user .* from .*", authlog) root_matches = re.findall("Disconnected from authenticating user root", authlog) logger.debug("Finished searching for logins") users = [] # list of users with format [username, number of logins] # for each item data = [] num = len(matches) # total number of logins for match in matches: # [('user', 'ip')] entry = re.search('^.*publickey\sfor\s(\w*)\sfrom\s(\S*)', match) user = entry.group(1) ip = entry.group(2) userhost = user + '@' + resolve(ip, fqdn=config.prefs.get("sshd", "sshd-resolve-domains")) users.append(userhost) logger.debug("Parsed list of authorised users") # Format authorised users auth_data = Data(subtitle=plural('login', num) + ' from', items=users) if (len(auth_data.items) == 1): # If only one user, do not display no of logins for this user logger.debug("Found {0} logins for user {1}".format( auth_data.orderbyfreq() auth_data.truncl(config.prefs.getint("logparse", "maxlist")) logger.debug("Found {0} logins for {1} users".format( len(matches), len(users))) section.append_data(auth_data) # Format invalid users invalid_users = [] for match in invalid_matches: # [('user', 'ip')] entry = re.search('^.*Invalid user (\S+) from (\S+).*', match) try: user = entry.group(1) ip = entry.group(2) except: # blank user field continue userhost = user + '@' + ip invalid_users.append(userhost) logger.debug("Parsed list of invalid users") invalid_data = Data(subtitle=plural("attempted login", len(invalid_matches)) + " from " + plural("invalid user", len(invalid_users), print_quantity=False), items=invalid_users) if (len(invalid_data.items) == 1): # If only one user, do not display no of logins for this user logger.debug("Found {0} login attempts for user {1}" .format(len(invalid_matches), invalid_data.items[0])) invalid_data.subtitle += ' ' + invalid_data.items[0] invalid_data.orderbyfreq() invalid_data.truncl(config.prefs.get("logparse", "maxlist")) logger.debug("Found {0} login attempts for invalid users" .format(len(invalid_matches))) section.append_data(invalid_data) logger.debug("Found {0} attempted logins for root". format(str(len(root_matches)))) section.append_data(Data(subtitle=plural("attempted login", str(len(root_matches))) + " for root")) logger.info("Finished sshd section") return section