Mini Shell

Direktori : /proc/self/root/opt/sharedrads/mitigatord/
Upload File :
Current File : //proc/self/root/opt/sharedrads/mitigatord/mitigatord

#!/opt/imh-python/bin/python3
import pdb
import os
import signal
import time
import datetime
import re
import argparse
import threading
from subprocess import check_output

class Mitigator():
    '''
    currently has two main features:
    1. watches for a queueprocd process related to jailshells, kills it
    2. repeatedly attemps to clear virtfs if there are mounts
    '''
    def __init__(self):
        self.log_file = '/var/log/mitigatord.log'
        self.virtfs_attempts = 0
        self.log_level = 2
        self.virt_check_interval = 3
        self.thread_list = []

    def get_args(self):
        '''
        flags: -d makes logging to
        log_file instead of stdout
        '''
        parser = argparse.ArgumentParser()
        parser.add_argument('-d', '--daemon', action='store_true',
            default=False, dest='daemon',
            help=('logs to log file instead of stdout'))
        self.args = parser.parse_args()
        # slows down process checking for daemon mode
        self.log(f'pid {os.getpid()} starting in daemon mode', 1)
        # convert minutes to seconds

    def proc_watcher(self):
        '''
        function to check for and kill
        the process that spawns jailshells
        '''
        search_str = re.compile(
            r'root\s+(\d+)[^\n]+queueprocd - process - update_users_jail\s*\n'
        )
        ps_aux = check_output('ps -fu root | grep -F queueprocd', shell=True, timeout = 60).decode('utf-8')
        # lightest string comparison I think
        if 'update_users_jail' not in ps_aux:
            self.log('proc not found', 3)
            return
        # then gets pid with re
        proc_finder = re.search(search_str, ps_aux)
        if not proc_finder:
            self.log('re.search failed, looping', 3)
            return
        pid = int(proc_finder.group(1))
        self.log(f'found:\n{proc_finder.group(0).strip()}', 1)
        try:
            os.kill(pid, signal.SIGKILL)
        except Exception as e:
            self.log(e, 1)
        return

    def clear_virt(self):
        '''
        runs proc_watcher
        clears umounts all virtfs mounts + orphans
        '''
        self.launch_thread('proc_watcher', self.proc_watcher)
        time.sleep(0.4)
        clear_cmd = ('grep -F " /home/virtfs/" /proc/mounts '
                     '''| awk '{print $2}' '''
                     '|  xargs -I {} -P 5 umount -v {} &>/dev/null;'
                     'echo -n')
        self.log('clearing virtfs mounts', 1)
        check_output(clear_cmd, shell=True, timeout=3600)
        self.log('clearing orphan mounts', 1)
        check_output(
            '/scripts/clear_orphaned_virtfs_mounts --clearall &>/dev/null',
            timeout=3600,
            shell=True,
        )
        self.log('done clearing virtfs mounts', 1)
    
    def check_virt(self):
        '''
        checks for virtfs mounts
        returns False if there are no virtfs mounts
        runs clear_virt and returns True if mounts

        '''
        count_cmd = ('grep -F " /home/virtfs/" /proc/mounts '
                     '''| awk '{print $2}' | wc -l 2>/dev/null''')
        virt_count = check_output(count_cmd, shell=True, timeout=60)
        virt_count = virt_count.decode('utf-8').strip()
        self.log(f'{virt_count} virtfs mounts', 2)
        if int(virt_count) == 0:
            self.log('no virt mounts found, looping', 2)
            return False
        else:
            self.log(f'{virt_count} virtfs mounts', 1)
            self.clear_virt()
            return True

    def virt_watcher(self):
        '''
        function for virtfs mount clearing loop
        '''
        while True:
            self.check_virt()
            time.sleep(self.virt_check_interval)

    def launch_thread(self, name, target):
        '''
        uses daemon false so we dont need to join threads
        '''
        t = threading.Thread(
            name=name,
            target=target, daemon = False
        )
        t.start()
        self.thread_list.append(t)        

    def log(self, log_str, lvl):
        '''
        provides logging with modular verbosity
        see self.log_level in __init__
        '''
        if lvl >= self.log_level:
            return
        tstamp =  datetime.datetime.now().replace(microsecond=0).isoformat()
        log_str = f'{tstamp}:{log_str}'
        if self.args.daemon:
            with open(self.log_file, 'a') as fh:
                if os.path.getsize(self.log_file) > 15000000:
                    fh.truncate(10000000)
                print(log_str, file=fh)
            return
        print(log_str)
        
def main():
    '''
    handles main thread launching
    '''
    m = Mitigator()
    m.get_args()
    m.launch_thread('virt_watcher', m.virt_watcher)

if __name__ == '__main__':
    main()

Zerion Mini Shell 1.0