Mini Shell

Direktori : /lib/fixperms/
Upload File :
Current File : //lib/fixperms/fixperms_main.py

"""Main logic for fixperms"""
import sys
import re
from functools import partial
from subprocess import run, PIPE, CalledProcessError
from concurrent.futures import ProcessPoolExecutor, as_completed
import traceback
import rads
from fixperms_cpanel import CpanelPermMap
from fixperms_cwp import CwpPermMap
from fixperms_wp3 import WP3PermMap
from fixperms_cli import parse_args, Args
from fixperms_ids import IDCache


def check_dso_without_modruid2(role: str):
    """Check if DSO is installed and modruid2 is disabled"""
    if rads.IMH_ROLE == 'shared':
        return  # no need to check on shared
    if role not in ('CWP', 'cPanel'):
        return
    run_cmd = partial(run, encoding='UTF-8', stdout=PIPE, check=False)
    # pylint: disable=unsupported-membership-test
    if role == 'CWP':
        mods = run_cmd(['/usr/local/apache/bin/httpd', '-M']).stdout
        # this is the same way /scripts/dso_handler_remove scans for DSO
        if not re.search(r'php\d+_module', mods):
            return
        good_mods = 'mod_ruid2 or mod_mpm_itk'
        kb_url = "http://wiki.centos-webpanel.com/dso-php-handler-for-cwp"
    else:
        php = run_cmd(
            ['/usr/local/cpanel/bin/rebuild_phpconf', '--current']
        ).stdout
        if 'SAPI: dso' not in php:
            return
        mods = run_cmd(['/usr/sbin/httpd', '-M']).stdout
        good_mods = 'ea-apache24-mod_ruid2 or ea-apache24-mod_mpm_itk'
        kb_url = "https://go.cpanel.net/EA4RecDSO"
    if 'ruid2_module (shared)' in mods or 'mpm_itk_module (shared)' in mods:
        return
    # CWP users might need to build it with /usr/local/apache/bin/apxs
    sys.exit(
        f"""Please install the modruid2 Apache module.

    fixperms detected a security issue and exited.
    PHP DSO runs as the nobody user by default. In a shared hosting environment,
    this is a security issue.  We strongly recommend that you install either the
    {good_mods} Apache
    module unless you have single-user system. If you use suPHP, you will add
    some security, but may experience performance issues on your server.

    For more information, see: {kb_url}"""
    )


def main():
    """Main program logic: iterate over each user and run fixperms"""
    args = parse_args()
    try:
        ids = IDCache(args.role)
    except KeyError as exc:
        args.logger.critical('%s. Cannot continue.', exc)
        sys.exit(1)
    check_dso_without_modruid2(args.role)
    if len(args.users) > 1 and args.procs > 1:
        parallel_execute(args, ids)
    else:
        serial_execute(args, ids)


def parallel_execute(args: Args, ids: IDCache):
    """Fork processes to handle each user"""
    exit_code = 0
    with ProcessPoolExecutor(max_workers=args.procs) as pool:
        futures = []
        for user in args.users:
            try:
                perm_map = get_perm_map(args, ids, user)
            except Exception as exc:
                if not isinstance(exc, CalledProcessError):
                    args.logger.debug(traceback.format_exc())
                args.logger.error(str(exc))
                exit_code = 1
                continue
            future = pool.submit(perm_map.run)
            futures.append(future)
        for future in as_completed(futures):
            try:
                future.result()
            except Exception as exc:
                if not isinstance(exc, CalledProcessError):
                    args.logger.debug(traceback.format_exc())
                args.logger.error(str(exc))
                exit_code = 1
                continue
    sys.exit(exit_code)


def serial_execute(args: Args, ids: IDCache):
    """Handle each user in the main process"""
    exit_code = 0
    for user in args.users:
        try:
            get_perm_map(args, ids, user).run()
        except Exception as exc:
            if not isinstance(exc, CalledProcessError):
                args.logger.debug(traceback.format_exc())
            args.logger.error(str(exc))
            exit_code = 1
            continue
    sys.exit(exit_code)


def get_perm_map(args: Args, ids: IDCache, user: str):
    """Return a PermMap subclass object"""
    if args.role == 'CWP':
        return CwpPermMap(ids, args, user)
    if args.role == 'cPanel':
        return CpanelPermMap(ids, args, user)
    if args.role == 'WP3':
        return WP3PermMap(ids, args)
    sys.exit(f"BUG in get_perm_map(): {args.role=}")


if __name__ == '__main__':
    main()

Zerion Mini Shell 1.0