File: //proc/self/root/opt/alt/python37/lib/python3.7/site-packages/orphanedaccountscanner/main.py
#! /opt/alt/python37/bin/python3
import os
import re
import json
import typing
import socket
import datetime
import requests
from typing import Dict
from config import oas_url
from utils.ranking import rank
dirs = {
'/home': {
'type': 'account'
},
}
ignore = [
'gdlinuxm',
'cpsupport',
'gdresell',
'gdmigrate',
'vpsmigrate',
'cpanelsolr',
'diablo',
'gdlegal',
'binlogs',
'cphulkd',
'gdlinuxm_wp2',
'horde',
'modsec',
'mysql',
'performance_schema',
'roundcube',
'ikvminit',
'srebackup',
'svc4xdmzoss1h9vet'
]
SSOT = {
'accounts': [],
'databases': []
}
LOCAL = {
'accounts': {},
'databases': {}
}
localSOT = '/home/diablo/non_orphan_accounts'
#'accounts' [{
# 'db_after_asr': {
# 'uid': 1,
# 'gid': 1,
# 'last_accessed': 1
# }
#},
#
#]
def system_health() -> bool:
for _ in dirs:
if not os.path.exists(_):
raise SystemError('Directory not found')
return True
def get_hostname() -> str:
if socket.gethostname() == str():
raise TypeError("Hostname audit event failed!")
return socket.gethostname().split('.')[0]
def check_hostname() -> bool:
"""
Grabs a servers unix hostname and checks if it's a cPanel server
Returns: bool
"""
short_name = get_hostname()
hostname_regex = '^(p3|sg2|sxb1|bom1)(p|t)l(m|z)cpnl\d{2,}$'
if re.search(hostname_regex, short_name):
return True
# Local account scanning
def directory_scan(dir) -> list:
"""
Parses a given directory and returns a list of sub directories ignoring
files and hidden dirs/files
Returns: list of dirs
"""
if dir not in ['/home', '/var/lib/mysql']:
raise TypeError('We have no idea how to scan that, sorry')
try:
entries = []
with os.scandir(dir) as scan_path:
for entry in scan_path:
if not entry.name.startswith('.') and entry.is_file():
# both parsers need dirs and not hidden
continue
else:
entries.append(entry)
except OSError as error_message:
raise SystemError(error_message)
return entries
def get_directory_info(dir: os.DirEntry, base_dir: str,) -> list:
stat = dir.stat()
if stat.st_gid == 199 or stat.st_gid == 0:
# Skip GDSTAFF and ROOT owned things
return
if os.path.islink(dir):
# Skip symlinks
return
if dir.name in ignore:
# Skip all things that we are explicitly ignoring
return
# If there's not a trailing / the name conc. doesn't work
if base_dir[-1] is not '/':
base_dir += '/'
#from subprocess import run
#process = run(['du', '-s', base_dir + dir.name], capture_output=True, text=True)
#size_in_kb = process.stdout.split('\t')[0]
size_in_kb = 0
return [ dir.name, stat.st_uid, stat.st_gid, stat.st_atime , size_in_kb ]
relevance_queries = {
'cpanel_migrations': {
'description': 'cpmove_ accounts'
}
}
removal_command = ['']
def process(accounts: Dict[str, Dict[str, str]], ssot):
real = []
rank_2 = []
rank_3 = []
rank_4 = []
for account in accounts:
rank = 0
for query in relevance_queries:
account_details = accounts[account]
if account_details['gid'] <= 9999:
rank = -1
if 'cpmove_' in account:
# query and rank significance
rank += 3
if account in ssot:
rank = -1
if account not in ssot:
rank += 3
if account in ignore:
rank = -1
rank = 4 if rank >= 4 else rank
if rank == 0 or rank == -1:
real.append((account, rank))
if rank == 1 or rank == 2:
rank_2.append((account, rank))
if rank == 3:
rank_3.append((account, rank))
if rank == 4:
rank_4.append((account, rank))
return real, rank_2, rank_3, rank_4
if __name__ == '__main__':
# Build a list of commands to ensure the host is operational to scan
verification_commands = [
check_hostname(),
system_health()
]
for _ in verification_commands:
if not _ == True:
raise SystemError('unable to verify server')
# Get data from source of truth
f = open(f'/home/diablo/non_orphan_accounts')
ssot = { 'users': [] }
for line in f:
ssot['users'].append(line.rstrip())
ACCOUNTS = ssot['users']
# Get data from local_ l_
l_accounts = directory_scan('/home')
for entry in l_accounts:
try:
name, uid, gid, st_atime, size = get_directory_info(entry, '/home/')
LOCAL['accounts'][name] = {
'uid': uid,
'gid': gid,
'st_atime': datetime.datetime.fromtimestamp(st_atime).strftime("%Y-%m-%d %I:%M:%S"),
'size': size
}
except Exception as e:
pass
real, rank_2, rank_3, rank_4= process(LOCAL['accounts'], ACCOUNTS)
print(len(rank_3), rank_3)