diff options
Diffstat (limited to 'client_manager.py')
| -rw-r--r-- | client_manager.py | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/client_manager.py b/client_manager.py new file mode 100644 index 0000000..84bf3df --- /dev/null +++ b/client_manager.py | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | |||
| 2 | # main logic | ||
| 3 | |||
| 4 | from sys_init import setup | ||
| 5 | setup() | ||
| 6 | |||
| 7 | import pyinotify | ||
| 8 | import subprocess | ||
| 9 | import re | ||
| 10 | import pwd | ||
| 11 | import os | ||
| 12 | import json | ||
| 13 | import atexit | ||
| 14 | import fcntl | ||
| 15 | |||
| 16 | def get_ssh_port(pid): | ||
| 17 | ''' | ||
| 18 | Jan 31 07:50:28 vultr sshd[43690]: Accepted publickey for root from 210.10.76.5 port 43730 ssh2: ED25519 SHA256:qz9ffMCb3vPlabn3ZHee00qIPBxkDiUiVSorcUkGdII | ||
| 19 | Jan 31 07:50:28 vultr sshd[43690]: pam_unix(sshd:session): session opened for user root(uid=0) by root(uid=0) | ||
| 20 | Jan 31 07:50:29 vultr sshd[43693]: Received disconnect from 210.10.76.5 port 43730:11: disconnected by user | ||
| 21 | Jan 31 07:50:29 vultr sshd[43693]: Disconnected from user root 210.10.76.5 port 43730 | ||
| 22 | Jan 31 07:50:29 vultr sshd[43690]: pam_unix(sshd:session): session closed for user root | ||
| 23 | ''' | ||
| 24 | ''' | ||
| 25 | # less efficient but readable | ||
| 26 | pid = '33216' | ||
| 27 | pids = [] | ||
| 28 | port = -1 | ||
| 29 | for l in lines: | ||
| 30 | l = l.split() | ||
| 31 | if pid == l[1]: | ||
| 32 | commonstring = l[8] | ||
| 33 | for l2 in lines: | ||
| 34 | if commonstring in l2.split(): | ||
| 35 | pids.append(l2.split()[1]) | ||
| 36 | for i in pids: | ||
| 37 | for l in lines: | ||
| 38 | l = l.split() | ||
| 39 | if i in l[1] and "*:" in l[8]: | ||
| 40 | port = l[8][2:] | ||
| 41 | ''' | ||
| 42 | try: | ||
| 43 | lines = subprocess.check_output("lsof -i -n | grep sshd", shell=True, text=True).splitlines() | ||
| 44 | pid = str(pid) | ||
| 45 | pids = {l.split()[1] for l in lines | ||
| 46 | if pid == l.split()[1] or | ||
| 47 | l.split()[8] in [x.split()[8] for x in lines if x.split()[1] == pid]} | ||
| 48 | |||
| 49 | port = next(l.split()[8][2:] for l in lines if l.split()[1] in pids and "*:" in l.split()[8]) | ||
| 50 | return port | ||
| 51 | except: | ||
| 52 | return -1 | ||
| 53 | |||
| 54 | def get_keyname(fingerprint): | ||
| 55 | auth_file = os.path.join(os.path.expanduser(f"~{user}"), ".ssh", "authorized_keys") | ||
| 56 | try: | ||
| 57 | result = subprocess.run(['ssh-keygen', '-lf', f'{auth_file}'], capture_output=True, text=True, shell=False, check=True) | ||
| 58 | # Raises CalledProcessError if command fails, for check = true | ||
| 59 | |||
| 60 | #256 SHA256:d9CBxSLBLzLjYGZDCsO6V+lddlN/elK1hGDBS56cbTo user@host (ED25519) | ||
| 61 | for line in result.stdout.strip().split('\n'): | ||
| 62 | parts = line.split() | ||
| 63 | if fingerprint in parts[1]: | ||
| 64 | return parts[2] | ||
| 65 | return 'not found' | ||
| 66 | |||
| 67 | except subprocess.CalledProcessError as e: | ||
| 68 | print(f"Error executing command: {e}") | ||
| 69 | return None | ||
| 70 | except Exception as e: | ||
| 71 | print(f"Error processing output: {e}") | ||
| 72 | return None | ||
| 73 | |||
| 74 | def write_data(data): | ||
| 75 | with open('/tmp/ssh_sessions.json', 'w') as f: | ||
| 76 | # Get exclusive lock for writing | ||
| 77 | fcntl.flock(f.fileno(), fcntl.LOCK_EX) | ||
| 78 | try: | ||
| 79 | # Clear file and write new data | ||
| 80 | f.seek(0) | ||
| 81 | json.dump(data, f) | ||
| 82 | f.truncate() | ||
| 83 | finally: | ||
| 84 | fcntl.flock(f.fileno(), fcntl.LOCK_UN) | ||
| 85 | |||
| 86 | def handle_log_change(event): | ||
| 87 | global last_position | ||
| 88 | with open(event.pathname, 'r') as f: | ||
| 89 | # Go to end and read new lines | ||
| 90 | f.seek(last_position) | ||
| 91 | new_lines = f.readlines() | ||
| 92 | last_position = f.tell() | ||
| 93 | |||
| 94 | for line in new_lines: | ||
| 95 | #print(f"New log: {line.strip()}") | ||
| 96 | line = line.strip() | ||
| 97 | if f"Accepted publickey for {user}" in line: | ||
| 98 | pid = re.search(r'\[(\d+)\]', line.split()[4]).group(1) | ||
| 99 | port = get_ssh_port(pid) | ||
| 100 | keyname = get_keyname(line.split()[15]) | ||
| 101 | srcip = line.split()[10] | ||
| 102 | #print(pid, port, keyname, srcip) | ||
| 103 | ssh_sessions[pid] = [srcip, keyname, port] | ||
| 104 | ssh_sessions[pid] = { | ||
| 105 | 'srcip': srcip, | ||
| 106 | 'key': keyname, | ||
| 107 | 'pubport': port | ||
| 108 | } | ||
| 109 | write_data(ssh_sessions) | ||
| 110 | if "pam_unix(sshd:session): session closed" in line: | ||
| 111 | pid = re.search(r'\[(\d+)\]', line.split()[4]).group(1) | ||
| 112 | if pid in ssh_sessions: | ||
| 113 | del ssh_sessions[pid] | ||
| 114 | else: | ||
| 115 | print("WARNING! PID NOT FOUND IN SESSION CACHE!") | ||
| 116 | write_data(ssh_sessions) | ||
| 117 | |||
| 118 | print("db: ",ssh_sessions) | ||
| 119 | |||
| 120 | |||
| 121 | |||
| 122 | user = "root" | ||
| 123 | |||
| 124 | # init last_position | ||
| 125 | global last_position | ||
| 126 | with open('/var/log/secure', 'r') as f: | ||
| 127 | f.seek(0, 2) | ||
| 128 | last_position = f.tell() | ||
| 129 | |||
| 130 | global ssh_sessions | ||
| 131 | ssh_sessions = {} | ||
| 132 | |||
| 133 | wm = pyinotify.WatchManager() | ||
| 134 | wm.add_watch('/var/log/secure', pyinotify.IN_MODIFY, handle_log_change) | ||
| 135 | notifier = pyinotify.Notifier(wm) | ||
| 136 | |||
| 137 | print("Watching /var/log/secure...") | ||
| 138 | notifier.loop() | ||
| 139 | |||
| 140 | |||
