Server IP : 184.154.167.98 / Your IP : 52.14.116.234 Web Server : Apache System : Linux pink.dnsnetservice.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 User : puertode ( 1767) PHP Version : 7.2.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /usr/share/cagefs/ |
Upload File : |
# -*- 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 # List of Actions # # Create /etc/cagefs/cagefs.base.home.dirs file for Plesk [ create_plesk_base_home_dirs(); ] # PostGreSQL configure for CageFS [ postgresql_configure(); ] # LiteSpeed configure for CageFS [ litespeed_configure(); ] # Exclude .cagefs folder from ISPManager backup [ install_ISPManager_directory_exclude(); ] # Disable ASSP Deluxe for CageFS # Configure php.ini path for ISP manager # CXS configure [ configure_cxs(); ] from __future__ import print_function from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals from future import standard_library standard_library.install_aliases() from builtins import * import itertools import cldetectlib as detect import os, pwd, shutil, sys import xml.dom.minidom as xml import subprocess from pkg_resources import parse_version import cagefslib from cagefslib import touch from cagefshooks import write_file_content import configparser import re import secureio from cagefs_ispmanager_lib import install_ispmanager_directory_exclude import cagefs_da_lib from clcagefslib.selector.configure import is_ea4_enabled, read_cpanel_ea4_php_conf from cagefsctl import PROXY_COMMANDS, check_cagefs_skeleton from clcommon.utils import mod_makedirs, get_file_lines, delete_line_from_file LITESPEED_XML = '' LSPHP5_PATH = '/usr/local/bin/lsphp' DEFAULT_POSTGRES_FOLDER = '/var/run/postgres' POSTGRES_CONF = '/etc/sysconfig/postgres' # file exists on CL5, CL6. the file does not exist on CL7 POSTGRES_CL7_FOLDER = '/var/run/postgresql' CXS_IGNORE_COMMAND = 'hdir:/.cagefs' PLESK_BASE_HOME_DIRS_FILE = '/etc/cagefs/cagefs.base.home.dirs' PLESK_PHP_SESSION_DIR = '/var/lib/php/session' DA_SHARED_DIR = '/usr/local/directadmin/shared' DA_BIN='/usr/local/directadmin/directadmin' # Plesk base home dirs def create_plesk_base_home_dirs(): if not detect.is_plesk(): return if os.path.isdir(PLESK_BASE_HOME_DIRS_FILE): secureio.print_error("Error: \"{}\" shouldn't be a folder" .format(PLESK_BASE_HOME_DIRS_FILE)) return current_vhosts_d_regexp = '^{}/[^/]+\n'.format(cagefslib.PLESK_VHOSTS_D) try: if os.path.exists(PLESK_BASE_HOME_DIRS_FILE): with open(PLESK_BASE_HOME_DIRS_FILE, 'r+') as f: content = f.readlines() if current_vhosts_d_regexp not in content: f.write(current_vhosts_d_regexp) else: with open(PLESK_BASE_HOME_DIRS_FILE, 'w') as f: f.write('mount_basedir=1\n') f.write(current_vhosts_d_regexp) os.chmod(PLESK_BASE_HOME_DIRS_FILE, 0o600) except (OSError, IOError) as e: secureio.print_error('Failed to write ', PLESK_BASE_HOME_DIRS_FILE, str(e)) BOX_TRAPPER_DIR = '/usr/local/cpanel/sys_cpanel/boxtrapper-message' def add_boxtrapper_dir_cpanel(): add_mount_to_cagefs_mp(BOX_TRAPPER_DIR, read_only=True) def add_php_session_dir_plesk(): add_mount_to_cagefs_mp(PLESK_PHP_SESSION_DIR, personal=True, perm='700') def add_mounts_for_clamav(): """ Add mounts related to ClamAV into cagefs.mp file. """ clamav_database_dirs = ('/usr/local/share/clamav', '/var/lib/clamav') for directory in clamav_database_dirs: add_mount_to_cagefs_mp(directory, read_only=True) def add_mounts_for_passenger(): """ Add mounts related to Phusion Passenger into cagefs.mp file. """ passenger_dirs = ( '/var/run/ea-passenger-runtime', '/usr/share/passenger', '/usr/libexec/passenger', ) for directory in passenger_dirs: add_mount_to_cagefs_mp(directory, read_only=False) def add_mount_to_cagefs_mp(line, read_only=False, personal=False, perm=''): if read_only and personal: raise ValueError('read_only and personal can`t be true in the same time') import cagefsctl if (personal or os.path.isdir(line)) and os.path.isfile('/etc/cagefs/cagefs.mp'): cagefsctl.check_mp_file() mp_config = cagefsctl.MountpointConfig( path=cagefsctl.ETC_MPFILE, skip_errors=True, skip_cpanel_check=True, ) if line + '\n' not in mp_config.common_mounts \ and line not in itertools.chain(mp_config.read_only_mounts, mp_config.personal_mounts, mp_config.splitted_by_username_mounts, mp_config.splitted_by_uid_mounts): if personal: line = '@' + line if perm: line = line + ',' + perm elif read_only: line = '!' + line f = open('/etc/cagefs/cagefs.mp', 'at') f.write(line.strip()+"\n") f.close() touch('/usr/share/cagefs/need.remount') # PostGreSQL configure for CageFS def postgresql_configure(): if detect.detect_postgresql(): if not os.path.isfile(POSTGRES_CONF): add_mount_to_cagefs_mp(POSTGRES_CL7_FOLDER) return True postgres_folder = detect.get_param_from_file(POSTGRES_CONF, "SOCK_DIR", "=") if postgres_folder == "": postgres_folder = DEFAULT_POSTGRES_FOLDER elif postgres_folder != DEFAULT_POSTGRES_FOLDER: try: os.symlink(postgres_folder, DEFAULT_POSTGRES_FOLDER) except (OSError,) as e: secureio.print_error('failed to create symlink', DEFAULT_POSTGRES_FOLDER, str(e)) return False try: pg_user = pwd.getpwnam('postgres') except (KeyError,) as e: secureio.print_error("failed to find 'postgres' user", str(e)) return False postgres_uid = pg_user.pw_uid postgres_gid = pg_user.pw_gid if not os.path.lexists(postgres_folder): try: mod_makedirs(postgres_folder, 0o755) except (OSError,) as e: secureio.print_error('failed to create', postgres_folder, str(e)) return False try: os.chown(postgres_folder, postgres_uid, postgres_gid) except (OSError,) as e: secureio.print_error('failed to change owner of', postgres_folder, str(e)) return False add_mount_to_cagefs_mp(DEFAULT_POSTGRES_FOLDER) return True return False ################################ LITESPEED SECTION ################################ # Open LiteSpeed XML config def litespeed_config_read(): global LITESPEED_XML if LITESPEED_XML == '': try: LITESPEED_XML = xml.parse(detect.LITESPEED_CONFIG_FILE) except: import traceback print(traceback.format_exc(), file=sys.stderr) secureio.print_error('bad ' + detect.LITESPEED_CONFIG_FILE + ' file') sys.exit(1) # Write LiteSpeed XML config def litespeed_config_write(): if detect.detect_enterprise_litespeed(): shutil.copyfile(detect.LITESPEED_CONFIG_FILE,detect.LITESPEED_CONFIG_FILE + '.cagefs') f = open(detect.LITESPEED_CONFIG_FILE, 'wb') f.write(LITESPEED_XML.toprettyxml(indent='', newl='', encoding='UTF-8')) f.close() # LiteSpeed enableLVE configure def litespeed_enableLVE_configure(force_value = None): if detect.detect_enterprise_litespeed(): litespeed_config_read() if force_value == None: new_value = 2 else: new_value = force_value try: enableLVE_value = LITESPEED_XML.getElementsByTagName("httpServerConfig")[0].getElementsByTagName('enableLVE')[0].firstChild.nodeValue result = enableLVE_value if (force_value != None or int(enableLVE_value) < 2): LITESPEED_XML.getElementsByTagName("httpServerConfig")[0].getElementsByTagName('enableLVE')[0].firstChild.nodeValue = str(new_value) result = new_value except IndexError: enableLVE = LITESPEED_XML.createElement('enableLVE') enableLVE_value = LITESPEED_XML.createTextNode(str(new_value)) enableLVE.appendChild(enableLVE_value) LITESPEED_XML.getElementsByTagName("httpServerConfig")[0].appendChild(enableLVE) result = new_value return result # LiteSpeed phpSuExec configure def litespeed_phpSuExec_configure(): if detect.detect_enterprise_litespeed(): litespeed_config_read() try: phpSuExec_value = LITESPEED_XML.getElementsByTagName("httpServerConfig")[0].getElementsByTagName('phpSuExec')[0].firstChild.nodeValue if (int(phpSuExec_value) != 1): LITESPEED_XML.getElementsByTagName("httpServerConfig")[0].getElementsByTagName('phpSuExec')[0].firstChild.nodeValue = str(1) except IndexError: phpSuExec = LITESPEED_XML.createElement('phpSuExec') phpSuExec_value = LITESPEED_XML.createTextNode(str(1)) phpSuExec.appendChild(phpSuExec_value) LITESPEED_XML.getElementsByTagName("httpServerConfig")[0].appendChild(phpSuExec) def check_extProcessorList(): """ CAG-914 Check if there is extProcessorList section If not, print doc link to configure LiteSpeed Starting from LSWS v5.3 external apps and script handlers are no longer required. """ litespeed_version = detect.get_litespeed_version() check = LITESPEED_XML.getElementsByTagName( "httpServerConfig")[0].getElementsByTagName('extProcessorList') # Show warning message about configuration only if version of LSWS is lower than 5.3 if not check and parse_version(litespeed_version) < parse_version('5.3'): print("No extProcessorList section in file:\n" + \ detect.LITESPEED_CONFIG_FILE + \ "\nPlease configure LiteSpeed Web Server " + \ "using Web Admin Console as discribed here:\n" + \ "https://docs.cloudlinux.com/php_selector/#litespeed-support", file=sys.stderr) return check # LiteSpeed runOnStartUp configure def litespeed_runOnStartUp_configure(): if detect.detect_enterprise_litespeed(): litespeed_config_read() try: check_nodelist = check_extProcessorList() if not check_nodelist: return True nodelist = check_nodelist[0].getElementsByTagName('extProcessor') for node in nodelist: if (str(node.getElementsByTagName('name')[0].firstChild.nodeValue) == 'lsphp5'): try: if (node.getElementsByTagName('runOnStartUp')[0].firstChild != None): runOnStartUp_value = str(node.getElementsByTagName('runOnStartUp')[0].firstChild.nodeValue) if not runOnStartUp_value in ('1','0'): node.getElementsByTagName('runOnStartUp')[0].firstChild.nodeValue = str(0) except IndexError: runOnStartUp = LITESPEED_XML.createElement('runOnStartUp') runOnStartUp_value = LITESPEED_XML.createTextNode(str(0)) runOnStartUp.appendChild(runOnStartUp_value) node.appendChild(runOnStartUp) except IndexError: import traceback print(traceback.format_exc(), file=sys.stderr) secureio.print_error('bad ' + detect.LITESPEED_CONFIG_FILE + ' file') sys.exit(1) # LiteSpeed extProcessorList->path change for php5 def litespeed_lsphp5_path_change(lsphp5_path = LSPHP5_PATH): """ LiteSpeed extProcessorList->path change for php5 """ if detect.detect_enterprise_litespeed(): litespeed_config_read() try: check_nodelist = check_extProcessorList() if not check_nodelist: return True nodelist = check_nodelist[0].getElementsByTagName('extProcessor') for node in nodelist: if (str(node.getElementsByTagName('name')[0].firstChild.nodeValue) == 'lsphp5'): node.getElementsByTagName('path')[0].firstChild.nodeValue = str(lsphp5_path) except IndexError: import traceback print(traceback.format_exc(), file=sys.stderr) secureio.print_error('bad ' + detect.LITESPEED_CONFIG_FILE + ' file') sys.exit(1) return True else: return False def custombuild_set_cagefs(option): """ Perform '/usr/local/directadmin/custombuild/build set cagefs' command """ try: subprocess.run( ['/usr/local/directadmin/custombuild/build', 'set', 'cagefs', option], check=True, ) except subprocess.CalledProcessError: return def custombuild_rewrite_confs(): """ Perform '/usr/local/directadmin/custombuild/build rewrite_confs' command """ try: subprocess.run( ['/usr/local/directadmin/custombuild/build', 'rewrite_confs'], check=True, ) except subprocess.CalledProcessError: return # LiteSpeed configure for selector def litespeed_configure_selector(): try: litespeed_lsphp5_path_change() litespeed_enableLVE_configure(2) litespeed_phpSuExec_configure() litespeed_runOnStartUp_configure() litespeed_config_write() return True except: return False def configure_open_litespeed(): """ OpenLitespeed configure for CageFS on DirectAdmin """ if detect.detect_open_litespeed() and detect.is_da(): custombuild_set_cagefs('yes') custombuild_rewrite_confs() return True return False # LiteSpeed configure for CageFS def litespeed_configure(): try: if int(litespeed_enableLVE_configure()) <= 2: litespeed_phpSuExec_configure() litespeed_config_write() return True except: return False ################################ END LITESPEED SECTION ################################ def disable_cagefs_for_assp_deluxe(): config_file = '/usr/local/assp/assp.cfg' if not detect.is_cpanel() or not os.path.isfile(config_file): return try: adm_domain = detect.get_param_from_file(config_file, 'sendAllSpam', ':=') parts = adm_domain.split('@') if len(parts) == 2: # adm email found adm_domain = parts[1] # adm domain not found if adm_domain == "": return # 2. Call /scripts/whoowns <admDomain>, determine user p = subprocess.Popen(['/scripts/whoowns', adm_domain], shell=False, stdin=open('/dev/null'), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True, cwd='/scripts/', text=True) user_name = p.stdout.read() # 3. create file /etc/cagefs/exclude/assp-deluxe with the name of the resulting user f = open('/etc/cagefs/exclude/assp-deluxe', 'w') f.write(user_name+'\n') f.close() os.chmod('/etc/cagefs/exclude/assp-deluxe', 0o600) except (OSError, IOError) as e: secureio.print_error('Failed to disable CageFS for ASSP Deluxe: ', str(e)) def get_native_settings(param_name): """ Return parameter and its value from native php.ini :param param_name: name of parameter in php.ini :type param_name: string """ cagefslib.read_native_conf() ini_file = cagefslib.orig_binaries['php.ini'] if is_ea4_enabled() and not os.path.isfile(ini_file): conf = read_cpanel_ea4_php_conf() if conf: try: # get default system php version selected via MultiPHP Manager in cPanel WHM default_php = conf['default'] except KeyError: return [] # ignore php.ini parameters whensystem default version is alt-php if not default_php.startswith('ea-php'): return [] ini_file = '/opt/cpanel/{}/root/etc/php.ini'.format(default_php) if os.path.isfile(ini_file): return [(param_name, detect.get_param_from_file(ini_file, param_name, '='))] secureio.print_error('failed to open file', str(ini_file)) return [] def get_global_php_settings(): """ Return settings from global_php.ini """ GLOBAL_INI = "/etc/cl.selector/global_php.ini" settings = [] if os.path.isfile(GLOBAL_INI): f = open(GLOBAL_INI) cfg = configparser.ConfigParser(interpolation=None, strict=False) try: cfg.readfp(f) except configparser.Error: return [] for sect in cfg.sections(): settings.extend(cfg.items(sect)) f.close() return settings def reconfigure_alt_settings(settings, overwrite_list = None): """ Replace or add settings in php.ini for all alt-php versions :param settings: list of tuples like [('date.timezone', 'Europe/Moscow'), ('error_log', 'error_log')] :param overwrite_list: list of options to overwrite; empty list [] == overwrite all the two options ('error_log', 'date.timezone') None == do not overwrite the options """ if not settings: return if overwrite_list == []: overwrite_list = ['error_log', 'date.timezone'] elif overwrite_list is None: overwrite_list = [] for alt_dir in cagefslib.get_alt_dirs(): path = os.path.join('/opt/alt/', alt_dir, 'etc/php.ini') if os.path.isfile(path): f = open(path, 'r') text = f.readlines() for setting in settings: changed = False prog = re.compile(";*\s*" + setting[0] + "\s*=.*") for i in reversed(range(len(text))): # pylint: disable=range-builtin-not-iterating result = prog.match(text[i]) if result: if changed: if text[i][0] != ";": text[i] = ";" + text[i] + '\n' else: param, value = text[i].split("=", 1) if param.strip() not in ['error_log', 'date.timezone'] or not value.strip() or param.strip() in overwrite_list: text[i] = setting[0] + " = " + setting[1] + '\n' changed = True if not changed: text.append(setting[0] + " = " + setting[1] + '\n') f.close() f = open(path, 'w') f.writelines(text) f.close() else: secureio.print_error('failed to open file', str(path)) def replace_alt_settings(options=None): """ Replace or add settings in php.ini for all alt-php versions :param options: list of options to overwrite; empty list [] == overwrite all the two options ('error_log', 'date.timezone') None == do not overwrite the options :type options: list """ overwrite_list = None if options != None: overwrite_list = [] if options: for arg in options: s = set(arg.split(',')) if not s.issubset(['error_log', 'date.timezone']): print('Error: incorrect parameter of --apply-global-php-ini option:') print('Please use 0, 1 or 2 parameters from the list: error_log, date.timezone') print('using --apply-global-php-ini without arguments applies all global php options including two above') sys.exit(1) overwrite_list.extend(s) settings = get_global_php_settings() if len([x for x in settings if x[0] == 'error_log']) == 0: settings.extend(get_native_settings('error_log')) if len([x for x in settings if x[0] == 'date.timezone']) == 0: settings.extend(get_native_settings('date.timezone')) reconfigure_alt_settings(settings, overwrite_list) #CXS hook install into /etc/cxs def configure_cxs(): if not detect.CXS_check(): return try: # Add exclusions for CageFS to /etc/cxs/cxs.ignore if os.path.isfile('/etc/cxs/cxs.ignore'): f = open('/etc/cxs/cxs.ignore', 'r') content = f.readlines() f.close() CXS_HOOK_INSTALLED = False for line in content: if line.find(CXS_IGNORE_COMMAND) != -1: CXS_HOOK_INSTALLED = True break if not CXS_HOOK_INSTALLED: content.append('\n' + CXS_IGNORE_COMMAND + '\n') write_file_content('/etc/cxs/cxs.ignore', content) else: write_file_content('/etc/cxs/cxs.ignore', CXS_IGNORE_COMMAND + '\n') os.chmod('/etc/cxs/cxs.ignore', 0o644) # Modify or Create /etc/cxs/cxs.default if os.path.isfile('/etc/cxs/cxs.default'): f = open('/etc/cxs/cxs.default', 'r') content = f.readlines() f.close() IGNORE_HOOK_INSTALLED = False for line in content: if line.strip().startswith('ignore=/etc/cxs/cxs.ignore'): IGNORE_HOOK_INSTALLED = True break if not IGNORE_HOOK_INSTALLED: content.append('\n' + 'ignore=/etc/cxs/cxs.ignore' + '\n') write_file_content('/etc/cxs/cxs.default', content) else: write_file_content('/etc/cxs/cxs.default', 'ignore=/etc/cxs/cxs.ignore\n') os.chmod('/etc/cxs/cxs.default', 0o644) except (OSError, IOError) as e: secureio.print_error('Failed to change CXS configuration for CageFS: ', str(e)) def _add_da_shared_dir_to_cagefs_mp(): """ Create '/usr/local/directadmin/shared' directory if it doesn't already exist and add a corresponding line into the '/etc/cagefs/cagefs.mp' file. This directory is intended for storing files available to all users. Recent versions of DA panel will create this directory themselves, creation of the directory in our code is made for backwards compatibility with older DA panels. """ if os.path.exists(DA_SHARED_DIR): add_mount_to_cagefs_mp(DA_SHARED_DIR) else: try: mod_makedirs(DA_SHARED_DIR, 0o755) except OSError as e: secureio.print_error('failed to create', DA_SHARED_DIR, str(e)) else: add_mount_to_cagefs_mp(DA_SHARED_DIR) def _configure_proxy_commands_file_for_da(): """ Add a line containing the path to DA binary into the 'proxy.commands' file if DA panel version < 1.62.8. If DA panel version >= 1.62.8 remove this line. Starting '1.62.8' version DA no longer supports having suid bit set on DA binary, version < 1.62.8 means DA binary have suid bit, it should be executed via proxyexec, hence, we should add a line that contains path to DA binary into the 'proxy.commands' file if it is not already there. """ da_binary_line = f'DIRECTADMIN={DA_BIN}' detect.getCP() if parse_version(detect.CP_VERSION) < parse_version('1.62.8'): # check if path to DA binary is already in 'proxy.commands' file # if not, add it into the file try: proxy_command_lines = get_file_lines(PROXY_COMMANDS) if da_binary_line not in (line.strip() for line in proxy_command_lines): if proxy_command_lines: proxy_command_lines[-1] = proxy_command_lines[-1].strip() + '\n' proxy_command_lines.append(da_binary_line + '\n') secureio.write_file_via_tempfile( ''.join(proxy_command_lines), PROXY_COMMANDS, 0o600) except OSError as e: secureio.print_error( 'failed to add', da_binary_line, 'into', PROXY_COMMANDS, str(e)) else: try: delete_line_from_file(PROXY_COMMANDS, da_binary_line) except OSError as e: secureio.print_error( 'failed to remove', da_binary_line, 'from', PROXY_COMMANDS, str(e)) if check_cagefs_skeleton(): # CAG-1182: update /usr/loca/directadmin/directadmin binary in CageFS while update of cagefs package subprocess.run(['/usr/sbin/cagefsctl', '--wait-lock', '--update-list'], input=f'{DA_BIN}\n', text=True) def directadmin_configure(): """ Configure CageFs for Directadmin panel. """ if not detect.is_da(): return _add_da_shared_dir_to_cagefs_mp() _configure_proxy_commands_file_for_da() def reconfigure_cagefs(): import cagefsctl if postgresql_configure(): cagefslib.detect_postgres() create_plesk_base_home_dirs() install_ispmanager_directory_exclude() disable_cagefs_for_assp_deluxe() cagefs_da_lib.configure_selector_for_directadmin() configure_cxs() # Apply changes to exclusions list cagefsctl.check_exclude() # Add the spamassassin directories to CageFs in cPanel if detect.is_cpanel(): cagefsctl.add_spamassassin_dirs_cpanel() add_boxtrapper_dir_cpanel() if detect.is_plesk(): add_php_session_dir_plesk() if detect.is_da(): directadmin_configure() cagefsctl.add_mount_for_php_apm() cagefsctl.add_mounts_for_ea_php_sessions() # CAG-706: add mount for emulation of /var/run/utmp inside CageFS add_mount_to_cagefs_mp(cagefslib.VAR_RUN_CAGEFS, personal=True, perm='700') add_mounts_for_clamav() add_mounts_for_passenger()