d703135ed8a54b45c279188eb9be5c60451b407a
   1#
   2#   sshd.py
   3#   
   4#   Find number of ssh logins and authorised users (uses /var/log/auth.log)
   5#   
   6#   NOTE: This file is now deprecated in favour of the newer journald mechanism
   7#   used in sshd-journald.py. This parser is still functional but is slower and
   8#   has less features. Please switch over if possible.
   9#
  10
  11import re
  12
  13from logparse.formatting import *
  14from logparse.util import readlog, resolve
  15from logparse import config
  16from logparse.load_parsers import Parser
  17
  18class Sshd(Parser):
  19
  20    def __init__(self):
  21        super().__init__()
  22        self.name = "sshd"
  23        self.info = "Find number of ssh logins and authorised users (uses /var/log/auth.log)"
  24        self.deprecated = True
  25        self.successor = "sshd_journald"
  26
  27    def parse_log(self):
  28
  29        logger.warning("NOTE: This sshd parser is now deprecated. Please use sshd-journald if possible.")
  30
  31        logger.debug("Starting sshd section")
  32        section = Section("ssh")
  33        logger.debug("Searching for matches in {0}".format(config.prefs.get("logs", "auth")))
  34        matches = re.findall('.*sshd.*Accepted publickey for .* from .*', readlog(config.prefs.get("logs", "auth")))    # get all logins
  35        logger.debug("Finished searching for logins")
  36
  37        logger.debug("Searching for matches in {0}".format(config.prefs.get("logs", "auth")))
  38        authlog = readlog(config.prefs.get("logs", "auth"))
  39       
  40        matches = re.findall('.*sshd.*Accepted publickey for .* from .*', authlog)    # get all logins
  41        invalid_matches = re.findall(".*sshd.*Invalid user .* from .*", authlog)
  42        root_matches = re.findall("Disconnected from authenticating user root", authlog)
  43        logger.debug("Finished searching for logins")
  44        
  45        users = []  # list of users with format [username, number of logins] for each item
  46        data = []
  47        num = len(matches)     # total number of logins
  48        for match in matches:
  49            entry = re.search('^.*publickey\sfor\s(\w*)\sfrom\s(\S*)', match)  # [('user', 'ip')]
  50
  51            user = entry.group(1)
  52            ip = entry.group(2)
  53
  54            userhost = user + '@' + resolve(ip, fqdn=config.prefs.get("sshd", "sshd-resolve-domains"))
  55            users.append(userhost)
  56        logger.debug("Parsed list of authorised users")
  57
  58        auth_data = Data(subtitle=plural('login', num) + ' from', items=users)
  59
  60        if (len(auth_data.items) == 1):             # if only one user, do not display no of logins for this user
  61            logger.debug("found " + str(len(matches)) + " ssh logins for user " + users[0])
  62            auth_data.subtitle += ' ' + auth_data.items[0]
  63        auth_data.orderbyfreq()
  64        auth_data.truncl(config.prefs.getint("logparse", "maxlist"))
  65        logger.debug("Found " + str(len(matches)) + " ssh logins for users " + str(data))
  66        section.append_data(auth_data)
  67
  68        invalid_users = []
  69        for match in invalid_matches:
  70            entry = re.search('^.*Invalid user (\S+) from (\S+).*', match)  # [('user', 'ip')]
  71
  72            try:
  73                user = entry.group(1)
  74                ip = entry.group(2)
  75            except:     # blank user field
  76                continue
  77
  78            userhost = user + '@' + ip
  79            invalid_users.append(userhost)
  80        logger.debug("Parsed list of invalid users")
  81        invalid_data = Data(subtitle=plural("attempted login", len(invalid_matches)) + " from " + plural("invalid user", len(invalid_users), print_quantity=False), items=invalid_users)
  82        if (len(invalid_data.items) == 1):             # if only one user, do not display no of logins for this user
  83            logger.debug("Found " + str(len(invalid_matches)) + " SSH login attempts for invalid user " + invalid_users[0])
  84            invalid_data.subtitle += ' ' + invalid_data.items[0]
  85        invalid_data.orderbyfreq()
  86        invalid_data.truncl(config.prefs.get("logparse", "maxlist"))
  87        logger.debug("Found " + str(len(invalid_matches)) + " SSH login attempts for invalid users " + str(data))
  88        section.append_data(invalid_data)
  89
  90        logger.debug("Found {0} attempted logins for root".format(str(len(root_matches))))
  91
  92        section.append_data(Data(subtitle=plural("attempted login", str(len(root_matches))) + " for root"))
  93
  94        logger.info("Finished sshd section")
  95        return section