Sindbad~EG File Manager
# -*- 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
from contextlib import suppress
from glob import iglob
from typing import Tuple
from secureio import disable_quota
from xray.internal.utils import user_context
from xray.reconfiguration.xray_ini import (
INI_LOCATIONS,
INI_USER_LOCATIONS,
INI_USER_LOCATIONS_WEBSITE_ISOLATION,
is_excluded_path
)
logger = logging.getLogger()
GLOBAL_INI_MARKER = '/opt/cloudlinux/flags/enabled-flags.d/xray-ini-global-mode.flag'
# Try to import website isolation check from securelve (cagefs)
try:
from clcagefslib.domain import is_website_isolation_allowed_server_wide
except ImportError:
def is_website_isolation_allowed_server_wide():
return False
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
# Copy to per-website directories
# (only when path exists! which means per website php selector is set)
if is_website_isolation_allowed_server_wide():
for location in INI_USER_LOCATIONS_WEBSITE_ISOLATION:
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!')
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists