/
opt
/
dedrads
/
/opt/dedrads
mkdir
upload
Name
Size
Mode
Actions
account_review/
-
0555
rm
check_software_mods/
-
0555
rm
cms_tools/
-
0555
rm
etc/
-
0555
rm
extras/
-
0555
rm
mailparse/
-
0555
rm
mysql/
-
0555
rm
nlp_scripts/
-
0555
rm
oldrads/
-
0555
rm
perl/
-
0555
rm
provision/
-
0555
rm
python/
-
0555
rm
suspended/
-
0555
rm
__pycache__/
-
0555
rm
account-review
799
0555
edit
dl
rm
allfw
6259
0555
edit
dl
rm
alp.py
16553
0555
edit
dl
rm
autossl_sync
6267
0555
edit
dl
rm
check_apache
9205
0555
edit
dl
rm
check_bandwidth
4546
0555
edit
dl
rm
check_boxtrapper
1684
0555
edit
dl
rm
check_cpu
12212
0555
edit
dl
rm
check_crons
1827
0555
edit
dl
rm
check_dcpumon
1973
0555
edit
dl
rm
check_dns
1827
0555
edit
dl
rm
check_domlogs
61
0555
edit
dl
rm
check_exim
3731
0555
edit
dl
rm
check_hacks
22604
0555
edit
dl
rm
check_imap
5249
0555
edit
dl
rm
check_io
6635
0555
edit
dl
rm
check_max_children
16341
0555
edit
dl
rm
check_mem
1660
0555
edit
dl
rm
check_misc
1510
0555
edit
dl
rm
check_pacct
5201
0555
edit
dl
rm
check_php
4344
0555
edit
dl
rm
check_pop3
2295
0555
edit
dl
rm
check_prov.py
4714
0555
edit
dl
rm
check_server
696
0555
edit
dl
rm
check_size
490
0555
edit
dl
rm
check_software
9849
0555
edit
dl
rm
check_spamd
2426
0555
edit
dl
rm
check_traffic
1933
0555
edit
dl
rm
check_user
1887
0555
edit
dl
rm
clean_exim.py
6390
0555
edit
dl
rm
clusterfix
5343
0555
edit
dl
rm
cmspass.py
3970
0555
edit
dl
rm
cms_check.py
9825
0555
edit
dl
rm
cms_counter.py
36734
0555
edit
dl
rm
cms_creds
713
0555
edit
dl
rm
cms_dumpdb
4485
0555
edit
dl
rm
cms_pw
1416
0555
edit
dl
rm
cpanel-api
7040
0555
edit
dl
rm
cpanel_postgres_manager.py
29004
0555
edit
dl
rm
cpmerge
4631
0555
edit
dl
rm
cpumon
2195
0555
edit
dl
rm
dcpumon.pl
1239
0555
edit
dl
rm
dedcheck
18127
0555
edit
dl
rm
dns-sync
14386
0555
edit
dl
rm
docroot.py
4425
0555
edit
dl
rm
du-tree
7450
0555
edit
dl
rm
envinfo.py
6633
0555
edit
dl
rm
exclude_rbl.py
5249
0555
edit
dl
rm
extract-vhost
2691
0555
edit
dl
rm
filescan
3566
0555
edit
dl
rm
find_warez
1460
0555
edit
dl
rm
first_setup.py
19120
0555
edit
dl
rm
fixwpcron.py
4822
0555
edit
dl
rm
fix_dns_cluster
353
0555
edit
dl
rm
goaccess
1217720
0555
edit
dl
rm
hostsfilemods
4467
0555
edit
dl
rm
imap_io
2323
0555
edit
dl
rm
innodb_converter.py
9343
0555
edit
dl
rm
killall911
530
0555
edit
dl
rm
killdns
941
0555
edit
dl
rm
lastcommcache.sh
1374
0555
edit
dl
rm
legal_lock_down.sh
7450
0555
edit
dl
rm
lil-cpanel
52002
0555
edit
dl
rm
listacct
4575
0555
edit
dl
rm
mailscan
4544
0555
edit
dl
rm
mail_sources.py
7407
0555
edit
dl
rm
megaclisas-status
38664
0555
edit
dl
rm
migrate2central.sh
14418
0555
edit
dl
rm
modify-account
40631
0555
edit
dl
rm
modsec_disable.py
11461
0555
edit
dl
rm
monarxctl
8912
0555
edit
dl
rm
msp.pl
27714
0555
edit
dl
rm
mysql_dstat
474
0555
edit
dl
rm
mysql_selector.py
73102
0555
edit
dl
rm
nlp
4582
0555
edit
dl
rm
procscrape
1863
0555
edit
dl
rm
quarantine
11083
0555
edit
dl
rm
radsfunctions.sh
863
0555
edit
dl
rm
recent-cp
16148
0555
edit
dl
rm
remote_dump
18347
0555
edit
dl
rm
reset_cpanel
3205
0555
edit
dl
rm
server-load
2192
0555
edit
dl
rm
show-conns
20105
0555
edit
dl
rm
show-conns-adv.py
54667
0555
edit
dl
rm
sparta.py
382498
0555
edit
dl
rm
sqltop
27129
0555
edit
dl
rm
telcheck
2411
0555
edit
dl
rm
temprootreset
186
0555
edit
dl
rm
unsuspend_user
1307
0555
edit
dl
rm
unsusprunner.sh
1840
0555
edit
dl
rm
updatednsadmin
526
0555
edit
dl
rm
update_spf
14972
0555
edit
dl
rm
upgrade-check
9216
0555
edit
dl
rm
vhost_data.py
6221
0555
edit
dl
rm
wp-xray.sh
85816
0555
edit
dl
rm
Edit:
/opt/dedrads/mail_sources.py
(7407B)
#! /usr/lib/rads/venv/bin/python3 '''List sources of email sent by address and directory.''' import os import sys import re import glob import gzip import datetime from collections import defaultdict from argparse import ArgumentParser __author__ = "Daniel K" __email__ = "danielk@inmotionhosting.com" def email_lines(all_logs=False): '''Return iterable over email log lines''' log_list = [] if all_logs: log_list = glob.glob('/var/log/exim_mainlog?*') for log_file in log_list: if not os.path.exists(log_file): print(f"Could not find log file: {log_file}") sys.exit(1) with gzip.open(log_file, 'r') as mail_log: try: yield from mail_log except OSError as error: print(f"Error reading file '{log_file}': {error}") sys.exit(1) log_file = "/var/log/exim_mainlog" if not os.path.exists(log_file): print(f"Could not find log file: {log_file}") sys.exit(1) with open(log_file, encoding='utf-8') as mail_log: try: yield from mail_log except OSError: print(f"Error reading file {log_file}") sys.exit(1) except UnicodeDecodeError as e: print(f"Received decoding error for {log_file}:") print(f"{e}") print("continuing...") def get_domains(username=''): '''Get domain regex for username''' if username == '': return r'[^@ ]+' domain_list = [] user_file = f"/var/cpanel/users/{username}" if not os.path.exists(user_file): print( "Could not find domains for {}. " "Invalid cPanel user? Cannot find {}".format(username, user_file) ) sys.exit(1) dns_rx = re.compile(r"^DNS[0-9]*=(.*)$") with open(user_file, encoding='utf-8') as mail_log: try: for line in mail_log: dns_match = dns_rx.search(line) if dns_match is not None: domain_list.append(dns_match.groups(1)[0]) except OSError as error: print(f"Error reading file '{user_file}': {error}") sys.exit(1) return '|'.join(domain_list) def get_sources(all_logs=False, username='', time=''): '''Returns touple of dicts of email sources''' email_logins = defaultdict(int) working_directories = defaultdict(int) spoofing = defaultdict(int) domains = get_domains(username) if time == '': date = '' duration = 0 elif '-' in str(time): date = time duration = 0 else: assert isinstance(time, int), "Time is not date or number" date = '' duration = int(time) target = datetime.datetime.now() datetime_rx = re.compile(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}') login_rx = re.compile( r'(courier|dovecot)_(plain|login):(?P<login>[^@ ]+(@(?P<domain>{}))?) ' r'.*for (?P<for>.*)$'.format(domains) ) spoofing_rx = re.compile( r'<= (?P<sender>[^@]*@[^@ ]+)' r'.*(courier|dovecot)_(plain|login):' r'(?P<login>(?!(?P=sender))[^@ ]+(@(?P<sdom>{}))?)' r'.*for (?P<for>.*)$'.format(domains) ) directory_rx = re.compile(fr'cwd=(?P<directory>/home/{username}[^ ]*)') for line in email_lines(all_logs): if date != '' and not line.startswith(date): continue if not datetime_rx.match(line): continue # If duration is set, skip any lines not within that duration if duration > 0 and not ( duration > ( target - datetime.datetime.strptime(line[:19], "%Y-%m-%d %H:%M:%S") ).total_seconds() ): continue rx_match = spoofing_rx.search(line.lower()) if rx_match: logged_in = "{} as {}".format( rx_match.group('login'), rx_match.group('sender') ) spoofing[logged_in] = spoofing[logged_in] + len( rx_match.group('for').split() ) rx_match = login_rx.search(line.lower()) if rx_match: address = rx_match.group('login') email_logins[address] = email_logins[address] + len( rx_match.group('for').split() ) continue rx_match = directory_rx.search(line) if rx_match: directory = rx_match.group('directory') if '/usr/local/cpanel/' in directory: continue working_directories[directory] = working_directories[directory] + 1 continue return (email_logins, working_directories, spoofing) def print_sorted_dict(dictionary): '''Print a dictionary sorted by values''' for value in sorted(dictionary, key=dictionary.get): print(f"{dictionary[value]:>7}\t{value}") def parse_args(): '''Parse command line aruments''' parser = ArgumentParser(description=__doc__) parser.add_argument( "-a", "--all", action='store_true', help="Search all email logs, rather than only the recent log.", ) parser.add_argument( 'username', metavar='USER', type=str, nargs='?', help="Search for only email from a specific cPanel account", ) time_group = parser.add_mutually_exclusive_group() time_group.add_argument( "-d", "--date", action='store', type=str, default='', help=( "Search for entries from a certain date. " "Must be in the format of YYYY-MM-DD." ), ) time_group.add_argument( "-s", "--seconds", action='store', type=int, default=0, help=( "Search entries which were made within the specified " "number of seconds. Overrides --all." ), ) time_group.add_argument( "-r", "--recent", action='store_true', help=( "Search recent entries, from the last hour. " "This is the same as -s 3600. Also overrides --all" ), ) args = parser.parse_args() all_logs = args.all if args.username is None: username = '' else: username = args.username date_rx = re.compile(r"\d{4}-\d{2}-\d{2}") if args.recent: time = 3600 all_logs = False elif args.date != '': if not date_rx.match(args.date): print(f"Date is not in the correct format: {args.date}") sys.exit(1) time = args.date elif args.seconds > 0: time = args.seconds all_logs = False else: time = '' return all_logs, username, time def main(): '''Main function for script''' (all_logs, username, time) = parse_args() (email_logins, working_directories, spoofing) = get_sources( all_logs, username, time ) print("Email Logins:") print_sorted_dict(email_logins) print("\nSource directories:") print_sorted_dict(working_directories) print("\nPossibly spoofed emails:") if not len(spoofing) == 0: print_sorted_dict(spoofing) else: print("\tNo obvious spoofs found") if __name__ == "__main__": main()
Save
cmd:
run