ok

Mini Shell

Direktori : /opt/cloudlinux/venv/lib/python3.11/site-packages/xray/reconfiguration/
Upload File :
Current File : //opt/cloudlinux/venv/lib/python3.11/site-packages/xray/reconfiguration/global_ini.py

# -*- coding: utf-8 -*-

# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2021 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT
import logging
import os
import re
import pwd
from contextlib import suppress
from glob import iglob
from typing import Tuple
from secureio import disable_quota

from xray.internal.utils import user_context

logger = logging.getLogger()

GLOBAL_INI_MARKER = '/opt/cloudlinux/flags/enabled-flags.d/xray-ini-global-mode.flag'

# directories that don't matter for us
# php is either outdated or just internal
_EXCLUDE_DIR_PATHS = (
    'php44', 'php51', 'php52', 'php53',
    'php\d+-imunify', 'php-internal'
)

# global set of ini locations where php
# usually loads configuration files from
# some of them may be missing, like /opt/plesk
# which only exists on plesk
_INI_LOCATIONS = (
    '/opt/alt/php[0-9][0-9]/link/conf',
    '/opt/cpanel/ea-php[0-9][0-9]/root/etc/php.d',
    '/opt/plesk/php/[0-9].[0-9]/etc/php.d',
    '/usr/local/php[0-9][0-9]/lib/php.conf.d',
    '/usr/share/cagefs/.cpanel.multiphp/opt/cpanel/ea-php[0-9][0-9]/root/etc/php.d',
    '/usr/share/cagefs-skeleton/usr/local/php[0-9][0-9]/lib/php.conf.d'
)

# same as above, but ini which are writeable by users
_INI_USER_LOCATIONS = (
    dict(path='/var/cagefs/*/*/etc/cl.php.d/alt-php[0-9][0-9]',
         user=lambda path: pwd.getpwnam(path.split('/')[4])),
)


def _is_excluded_path(dir_path: str) -> list:
    """
    Check if given path is in exclude list.
    """
    res = [substring for substring in _EXCLUDE_DIR_PATHS
           if re.search(substring, dir_path)]
    return res


def _iter_existing_ini_locations() -> Tuple[Tuple[int, int], str]:
    """
    Generator of existing paths (matching known wildcard locations)
    for additional ini files
    Returns tuple of (uid, gid) and path.
    """
    for location in _INI_LOCATIONS:
        for dir_path in iglob(location):
            if _is_excluded_path(dir_path):
                continue
            yield (0, 0), dir_path

    for location in _INI_USER_LOCATIONS:
        for dir_path in iglob(location['path']):
            if _is_excluded_path(dir_path):
                continue

            try:
                pw_record = location['user'](dir_path)
            except:
                logger.info('Unable to get information about user '
                            'owning %s directory (maybe he`s already terminated?), '
                            'skip updating', dir_path)
                continue
            else:
                yield (pw_record.pw_uid, pw_record.pw_gid), dir_path


def _create_single_ini(uid: int, gid: int, ini_path: str):
    # write counter of tasks so during mode switch
    # we can still safely cleanup ini files not
    # bound to any exiting tasks
    ini_content = ';xray.tasks=0\nextension=xray.so'

    path = os.path.join(ini_path, 'xray.ini')
    if os.path.exists(path):
        return

    with user_context(uid, gid), \
            disable_quota(), \
            open(path, 'w') as ini:
        logger.info('Generating %s file...', path)
        ini.write(ini_content)


def is_global_ini_mode():
    return os.path.exists(GLOBAL_INI_MARKER)


def create_global_ini_mode_marker():
    open(GLOBAL_INI_MARKER, 'w').close()


def remove_global_ini_mode_marker():
    with suppress(FileNotFoundError):
        os.remove(GLOBAL_INI_MARKER)


def create_ini_files() -> None:
    """
    Place xray.ini into each existing Additional ini path,
    including cagefs ones.
    """
    logger.info('Generating xray.ini files...')
    for (uid, gid), ini_path in _iter_existing_ini_locations():
        try:
            _create_single_ini(uid, gid, ini_path)
        except PermissionError:
            logger.warning('Unable to update file %s, '
                           'possible permission misconfiguration', ini_path)
            continue
        except Exception as e:
            logger.warning('Unexpected error happened during file processing: '
                           '"%s", error: "%s"', ini_path, str(e), exc_info=True)
            continue
    logger.info('Finished!')


def remove_ini_files() -> None:
    """
    Remove all gathered clos_ssa.ini files
    """
    logger.info('Removing clos_ssa.ini files...')
    for (uid, gid), clos_ini_dir in _iter_existing_ini_locations():
        ini_file = os.path.join(clos_ini_dir, 'xray.ini')
        try:
            with user_context(uid, gid), open(ini_file) as f:
                contents = f.read()

                # unlink file only if there are no linked tasks
                # case with minus sign covers negative values
                if "xray.tasks=0" in contents or \
                        "xray.tasks=-" in contents:
                    os.unlink(ini_file)
        except FileNotFoundError:
            continue
        except Exception as e:
            logger.warning('Unable to remove file: "%s", error: "%s"', ini_file, str(e))
            continue

    logger.info('Finished!')

Zerion Mini Shell 1.0