Failed to save the file to the "xx" directory.

Failed to save the file to the "ll" directory.

Failed to save the file to the "mm" directory.

Failed to save the file to the "wp" directory.

403WebShell
403Webshell
Server IP : 66.29.132.124  /  Your IP : 3.145.66.195
Web Server : LiteSpeed
System : Linux business141.web-hosting.com 4.18.0-553.lve.el8.x86_64 #1 SMP Mon May 27 15:27:34 UTC 2024 x86_64
User : wavevlvu ( 1524)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /opt/cloudlinux/venv/lib64/python3.11/site-packages/clselect/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /opt/cloudlinux/venv/lib64/python3.11/site-packages/clselect/clextselect.py
# -*- coding: utf-8 -*-

# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2019 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT

from __future__ import absolute_import
from __future__ import print_function
from __future__ import division
import collections
import configparser
import os
import operator

from clcommon.clcagefs import in_cagefs

from .clselect import ClSelect
from .clselectexcept import ClSelectExcept
from .clselectprint import clprint
from . import utils

# dependencies modulse dict. Example { 'ext_name': 'ext1' } - ext1 depends from ext_name
depend_modules_dict = dict()


class ClExtSelect(ClSelect):
    CONFLICTS_PATH = (
        '/etc/cl.selector.conf.d/php.extensions.conflicts'
        if in_cagefs()
        else '/etc/cl.selector/php.extensions.conflicts'
    )
    SYSTEM_ALT_PATH = '/opt/alt'

    def __init__(self, item='php'):
        ClSelect.__init__(self, item)
        self._conflicts = []
        # Sets in _get_enabled_extensions method
        #  True  - extension list was read from native php built-ins
        #  False - extension list was read from /etc/cl.selector/defaults.cfg
        self._use_default_exts_from_native_php = False

    def _is_disabled_extention(self, ext_name):
        return ext_name in self._hidden_extensions

    def enable_extensions(self, version, ext_list):
        """
        Adds extensions to default list of extensions for a version
        """
        alternatives = self.get_all_alternatives_data()
        self._check_alternative(version, alternatives)
        defaults_contents = self._process_ini_file(
            self.DEFAULTS_PATH,
            (self._item, version),
            self._add_extensions,
            ext_list, action = 'enable_extentions')
        self._write_to_file(
            '\n'.join(defaults_contents), ClExtSelect.DEFAULTS_PATH)

    def replace_extensions(self, version, ext_list):
        """
        Replaces extensions to default list of extensions for a version.
        Writes/updates /etc/cl.selector/defaults.cfg file
        :param version: alt-php version to process
        :param ext_list: list extensions to set as defaults for the version
        """
        alternatives = self.get_all_alternatives_data()
        self._check_alternative(version, alternatives)
        defaults_contents = self._process_ini_file(
            self.DEFAULTS_PATH,
            (self._item, version),
            self._replace_extensions,
            ext_list)
        self._write_to_file(
            '\n'.join(defaults_contents), self.DEFAULTS_PATH)

    def disable_extensions(self, version, ext_list):
        """
        Removes extensions from default list of extensions for a version
        :param version: alt-php version to process
        :param ext_list: comma separated extensions list to delete
        """
        alternatives = self.get_all_alternatives_data()
        self._check_alternative(version, alternatives)
        defaults_contents = self._process_ini_file(
            self.DEFAULTS_PATH,
            (self._item, version),
            self._del_extensions,
            ext_list, action = 'disable_extentions')
        self._write_to_file('\n'.join(defaults_contents), self.DEFAULTS_PATH)

    def list_extensions(self, version):
        """
        Returns list of extensions marking built-ins and enabled ones
        Also replaces mysqli->nd_mysqli in defaults.cfg for new installations according to LVEMAN-1399
        :param version: php version
        :return Tuple: (extension_name, extension_state)
            extension_state:
                None        -- built-in extension
                False/True  -- disabled/enabled extension
        """
        ext_mysqli_name = 'mysqli'
        ext_nd_mysqli_name = 'nd_mysqli'
        ext_list_to_write = list()
        is_need_to_write_defaults = False
        alternatives = self.get_all_alternatives_data()
        self._check_alternative(version, alternatives)
        # Get extensions list from /etc/cl.selector/defaults.cfg for supplied verson or
        # list of built-in extesions for native if version does not present in defaults.cfg
        enabled_extensions = self._get_enabled_extensions(version)
        # Get extension list for version
        as_built_in = self._get_builtins(version)
        try:
            # Get extensions list for version - list of files
            # /opt/alt/phpXX/etc/php.d.all/*.ini without .ini extension
            # Without dependencies analysis
            as_extensions = self._load_extensions_list(version)
        except ClSelectExcept.UnableToGetExtensions:
            as_extensions = []
        # ['bz2', 'calendar'] -> ('bz2', None), ('calendar', None)
        all_extensions = list(map((lambda i: (i, None)), as_built_in))
        for ext in as_extensions:
            status = False
            if (ext in enabled_extensions) and (ext not in as_built_in):
                status = True
            ext_set = set([(ext, True), (ext, False), (ext, None)])
            if not set(all_extensions).intersection(ext_set):
                # add ext and its status to result list
                # LVEMAN-1399:
                # If defaults modules was taken from native php built-ins
                # replace mysqli to nd_mysqli (if it exist) and set status True to it
                if ext == ext_mysqli_name and self._use_default_exts_from_native_php\
                        and ext_nd_mysqli_name in as_extensions:
                    all_extensions.append((ext_mysqli_name, False))
                    all_extensions.append((ext_nd_mysqli_name, True))
                    # After module replacement we need to write new list as defaults
                    is_need_to_write_defaults = True
                    # add nd_mysqli to list for write
                    ext_list_to_write.append(ext_nd_mysqli_name)
                else:
                    all_extensions.append((ext, status))
                    if status:
                        # if module enabled, add it to list for write
                        ext_list_to_write.append(ext)
        # all_extensions example: [('bz2', None), ('calendar', None), (u'zip', True), (u'zmq', False)]
        # If module replacement occures, write list to defaults.cfg
        if is_need_to_write_defaults:
            self.replace_extensions(version, ext_list_to_write)
        return tuple(sorted(all_extensions, key=operator.itemgetter(0)))

    def _get_enabled_extensions(self, version):
        """
        Returns list of enabled extensions for a version
        """
        try:
            # reads extensions list from /etc/cl.selector/defaults.cfg
            data = self._dh.get(
                "%s%s" % (self._item, version), 'modules')
            self._use_default_exts_from_native_php = False
            return list(map((lambda i: i.strip()), data.split(',')))
        except (configparser.NoSectionError, configparser.NoOptionError):
            self._use_default_exts_from_native_php = True
            return self._get_builtins('native')

    def _add_extensions(self, section_info, section, data, trace=True):
        """
        Adds 'modules' option to section or extends it
        @param section_info: tuple (item and version)
        @param section: list
        @param data: list
        @return: list
        """
        section_header = self._make_section_header(section_info)
        if len(section) == 0 or section_header != section[0]:
            return section
        midx = None
        modules = []
        alt_path = self._compose_alt_path(section_info[1])
        for idx in range(len(section)):
            if section[idx].startswith('modules'):
                midx = idx
                break
        if midx:
            modules_string = section[midx][section[midx].find('=')+1:].strip()
            modules.extend(
                list(map((lambda i: i.strip()), modules_string.split(','))))
        modules.extend(data)
        modules = self._check_for_conflicts(modules)
        resolved_modules = self._include_dependencies(modules, alt_path)
        modules_string = 'modules = %s' % (','.join(sorted(resolved_modules)))
        if midx:
            section[midx] = modules_string
        else:
            section.append(modules_string)
        return self._smooth_data(section)

    def _replace_extensions(self, section_info, section, data, trace=True):
        """
        Adds 'modules' option to section or extends it
        @param section_info: tuple (item and version).
            Example: ('php', '5.2')
        @param section: list. Modules from /etc/cl.selecto/defaults.cfg for supplied php version
            Example: ['[php5.2]',
                      'modules = bcmath,dom,gd,imap,json,mcrypt,mysql,mysqli,phar,posix,sockets,uuid,wddx,xmlreader,zip',
                      '', '']
        @param data: list: Modules list to set from command line
        @:param trace: ????, Currently not using, always True
        @return: list
        """
        global depend_modules_dict
        section_header = self._make_section_header(section_info)
        if len(section) == 0 or section_header != section[0]:
            return section
        midx = None
        alt_path = self._compose_alt_path(section_info[1])
        for idx in range(len(section)):
            if section[idx].startswith('modules'):
                midx = idx
                break
        modules = data[:]
        if trace:
            resolved_modules = set()
            modules = self._check_for_conflicts(modules)
            for mod in modules:
                include_dep = self._include_dependencies([mod], alt_path)
                if len(include_dep) != 1:
                    # Dependencies found, add them to depend_modules_dict
                    # Add deps to dict
                    depend_modules_dict.update({dep_module: mod for dep_module in include_dep if dep_module != mod})
                resolved_modules.update(include_dep)
            modules_string = 'modules = %s' % (','.join(sorted(resolved_modules)))
        else:
            modules_string = 'modules = %s' % (','.join(sorted(data)))
        if midx:
            section[midx] = modules_string
        else:
            section.append(modules_string)
        # Cleanup dependency list - remove from dependencies all modules, present in command line
        modules = depend_modules_dict.copy()
        for dep_module in modules.keys():
            if dep_module in data:
                del depend_modules_dict[dep_module]
        return self._smooth_data(section)

    def _del_extensions(self, section_info, section, data, trace=True):
        """
        Deletes items in data list from section list
        @param section_info: tuple (item and version)
        @param section: list
        @param data: list of extension names to delete
        @return: list
        """
        section_header = self._make_section_header(section_info)
        if len(section) == 0 or section_header != section[0]:
            return section
        midx = None
        alt_path = self._compose_alt_path(section_info[1])
        for idx in range(len(section)):
            if section[idx].startswith('modules'):
                midx = idx
                break
        if not midx:
            return section
        modules_string = section[midx][section[midx].find('=')+1:].strip()
        modules = set(map((lambda i: i.strip()), modules_string.split(',')))
        resolved_modules = modules.copy()
        for item in set(data):
            if item not in modules:
                continue
            rest_of_modules = modules.difference([item])
            if self._is_dependency(item, rest_of_modules, alt_path):
                continue
            resolved_modules.discard(item)
        resolved_modules = self._include_dependencies(resolved_modules, alt_path)
        modules_string = 'modules = %s' % (','.join(sorted(resolved_modules)))
        section[midx] = modules_string
        return self._smooth_data(section)

    def _is_dependency(cls, ext, modules, alt_path):
        """
        Checks if module in modules dependent on ext and returns true or false
        @param ext: Module to check
        @param modules: set of names of installed modules
        @param alt_path: Path to alt-php ini dir: /opt/alt/phpXX/etc/php.d.all
        @return: bool. True if ext present in dependencies of any module in modules list
        """
        global depend_modules_dict
        for mod in modules:
            dependencies = cls._get_dependencies(mod, alt_path)
            if ext in dependencies:
                depend_modules_dict[ext] = mod
                return True
        return False
    _is_dependency = classmethod(_is_dependency)

    def _compose_alt_path(self, version):
        """
        Composes and returns path for alternatives
        """
        return os.path.join(
            self.SYSTEM_ALT_PATH,
            "%s%s" % (self._item, version.replace('.', '')),
            "etc",
            "%s.d.all" % (self._item,))

    def _include_dependencies(cls, ext_list, alt_path, data=None):
        """
        Includes dependencies into extensions list and update data dict
        if present
        @param ext_list: list
        @param alt_path: string
        @param data: dict
        @return: list
        """
        in_section = False
        result_ext_list = []
        handled = set()
        q = collections.deque(ext_list)

        while q:
            ext = q.popleft()
            if ext in handled:
                continue

            handled.add(ext)

            ext_path = os.path.join(alt_path, f'{ext}.ini')
            try:
                f = open(ext_path)
                file_contents = []
                pending_contents = []

                for line in f:
                    if line.startswith('extension') or line.startswith('zend_extension'):
                        ext_name = cls._single_out_extension(ext, line)
                        if ext_name != ext and ext_name not in handled:
                            q.appendleft(ext_name)
                            continue

                        file_contents.append(f';---{ext}---')
                        in_section = True
                        file_contents.extend(pending_contents)
                        pending_contents = []

                    if not (line.startswith(';') or line.startswith('\n')):
                        if in_section:
                            file_contents.append(line.rstrip())
                        else:
                            pending_contents.append(line.rstrip())
                f.close()

                if data is not None and ext not in data:
                    data[ext] = file_contents

                # Adding to the beggining of the result list due to LVEMAN-504
                result_ext_list.insert(0, ext)
            except (OSError, IOError):
                continue

        return result_ext_list
    _include_dependencies = classmethod(_include_dependencies)

    def _get_dependencies(cls, ext, alt_path):
        """
        Checks if an extension has dependencies and if so returns them
        Otherwise returns None
        @param ext: string
        @return: set
        """
        dependencies = set()
        ext_path = os.path.join(alt_path, "%s.ini" % (ext,))
        try:
            f = open(ext_path)
            for line in f:
                if line.startswith('extension'):
                    ext_name = cls._single_out_extension(ext, line)
                    if ext_name != ext:
                        dependencies.add(ext_name)
            return dependencies
        except (OSError, IOError):
            return dependencies
    _get_dependencies = classmethod(_get_dependencies)

    def _single_out_extension(ext, line):
        """
        Singles out and returns extension from line
        """
        quirks = {'ixed': 'sourceguardian'}
        if '/' in line:
            ext_name = line[line.rfind('/')+1:].strip()
        else:
            ext_name = line[line.find('=')+1:].strip(' "')
        if '.' in ext_name:
            ext_name = ext_name[:ext_name.find('.')]
        if '-' in ext_name:
            ext_name = ext_name[:ext_name.rfind('-')]
        if ext_name in quirks:
            ext_name = quirks[ext_name]
        elif ext in ext_name:
            ext_name = ext
        elif ('_' in ext and ''.join(map((lambda i: i.capitalize()),
                ext.split('_'))) == ext_name):
            ext_name = ext
        return ext_name
    _single_out_extension = staticmethod(_single_out_extension)

    def _check_for_conflicts(self, ext_list):
        """
        Removes from extensions list conflicting ones
        """
        if not self._conflicts:
            self._load_conflicting_extensions()
        clean_set = set()
        for ext in ext_list:
            if self._is_not_conflicting(ext, clean_set) and \
                    not self._is_disabled_extention(ext):
                clean_set.add(ext)
            #else:
                #clprint.print_diag(
                #    'text',
                #    {'status': 'WARN',
                #     'message': '%s skipped as conflicting (%s)' % (ext, str(clean_set))})
        return clean_set

    def _is_not_conflicting(self, ext, clean_set):
        """
        Checks extension against conflicting sets
        """
        for conflict in self._conflicts:
            if ext in conflict:
                if len(clean_set.copy().intersection(conflict)) != 0:
                    return False
        return True

    def _load_conflicting_extensions(self):
        """
        Loads conflicting extensions from file and saves'em as list of sets
        """
        conflicts = utils.read_file_as_string(self.CONFLICTS_PATH)
        for line in conflicts.splitlines():
            if ',' not in line:
                continue
            conflict_set = set(map((lambda i: i.strip()), line.split(',')))
            if len(conflict_set) < 2:
                continue
            self._conflicts.append(conflict_set)

    def _load_extensions_list(self, version):
        """
        Loads alternative extensions list for a version
        @param version: string
        """
        alt_path = self._compose_alt_path(version)
        try:
            alt_extensions = []
            for filename in os.listdir(alt_path):
                if not filename.endswith('.ini'):
                    continue
                extension = filename[:filename.find('.ini')]
                if extension in self._hidden_extensions:
                    continue
                alt_extensions.append(extension)
            return sorted(alt_extensions)
        except OSError:
            raise ClSelectExcept.UnableToGetExtensions(version)

    @staticmethod
    def _print_dependencies_info(dependens_info):
        """
        Prints info
        @param ext: string
        @param data: list
        """
        for (i, ext) in dependens_info:
            clprint.print_diag(
                'text',
                {'status': 'WARN',
                 'message': '%s enabled as dependency (%s)'
                 % (i, ext)})

    @staticmethod
    def get_dependencies_list(ext, data, ext_list):
        """
        Get array of dependenses [(ext, depending ext)]
        @param ext: string
        @param data: list
        """
        if not data:
            return []
        diff = set(data).difference([ext])
        return [(i, ext) for i in diff if i not in ext_list]

    @staticmethod
    def get_conflicts_info(init_list, processed_set):
        return list(set(init_list).difference(processed_set))

    @staticmethod
    def _print_conflicts_info(diff):
        """
        Prepares data for printing conflicts if any
        @param init_list: list
        @param processed_set: set
        """
        if diff:
            for i in diff:
                clprint.print_diag(
                    'text',
                    {'status': 'WARN',
                     'message': '%s skipped as conflicting' % (i,)})

Youez - 2016 - github.com/yon3zu
LinuXploit