D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
cloudlinux
/
venv
/
lib
/
python3.11
/
site-packages
/
clcagefslib
/
webisolation
/
Filename :
jail_config_builder.py
back
Copy
#!/opt/cloudlinux/venv/bin/python3 -sbb # -*- coding: utf-8 -*- # # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2025 All Rights Reserved # # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT # """ Builder for website isolation jail mount configurations. Collects user docroots and isolation settings, then generates the complete jail mount configuration. """ import logging from pathlib import Path from clcommon import ClPwd from clcommon.cpapi import userdomains from clcommon.cpapi.cpapiexceptions import NoPanelUser from ..io import write_via_tmp from . import config, jail_utils from .jail_config import MountConfig from .mount_config import IsolatedRootConfig from .mount_ordering import build_docroot_tree, process_ordered_mounts from .mount_types import MountType class JailMountsConfigBuilder: """ Builder for generating jail mount configuration files. Collects docroots and isolation settings, then generates the mount configuration string for the jail.c implementation. """ def __init__(self, user: str): self.user = user self._all_docroots: set[str] = set() self._isolated_docroots: set[str] = set() self._phpselector_docroots: set[str] = set() def add_docroot(self, docroot: str) -> None: """Register a docroot path for the user.""" self._all_docroots.add(docroot) def enable_isolation(self, docroot: str) -> None: """Mark a docroot as requiring isolation.""" self._isolated_docroots.add(docroot) def enable_phpselector(self, docroot: str) -> None: """Enable per-domain PHP selector for a docroot.""" self._phpselector_docroots.add(docroot) def build(self) -> str: """ Generate the complete mount configuration. Returns: Configuration string in jail.c mount syntax. """ pw = ClPwd().get_pw_by_name(self.user) homedir = pw.pw_dir uid, gid = pw.pw_uid, pw.pw_gid # Build docroot tree once for all isolated docroots tree = build_docroot_tree(self._all_docroots) # Generate config for each isolated docroot generated_configs = [] for docroot in sorted(self._isolated_docroots, key=len): split_storage_base = jail_utils.full_website_path(homedir, docroot) home_overlay = IsolatedRootConfig( root_path=f"{split_storage_base}/home", target=homedir, persistent=True ) # Process ordered mounts for this isolated docroot docroot_mounts = process_ordered_mounts( active_docroot=docroot, tree=tree, uid=uid, gid=gid ) jail_config = MountConfig(uid=uid, gid=gid) # Add storage for the overlay'ed dir jail_config.add_overlay(home_overlay) # open .clwpos directory to make redis.sock available awp_path = f"{homedir}/.clwpos" home_overlay.mount(MountType.BIND, awp_path, awp_path, ("mkdir",)) # Add docroot mounts (from tree processing) # Mount them into already created overlay for mount in docroot_mounts: home_overlay.mount(mount.type, mount.source, mount.target, mount.options) # Apply mounts from isolated root and close target directory jail_config.close_overlay(home_overlay) # Home directory is already overlayed, we can apply per-domain mounts directly jail_config.add(MountType.USER_MOUNTS, "/") # php selector mounts (only when per-domain PHP selector is enabled) if docroot in self._phpselector_docroots: jail_config.add( MountType.BIND, source=f"/etc/cl.selector/{jail_utils.get_website_id(docroot)}", target="/etc/cl.selector" ) jail_config.add( MountType.BIND, source=f"/etc/cl.php.d/{jail_utils.get_website_id(docroot)}", target="/etc/cl.php.d" ) # Override proxyexec token with website specific folder jail_config.add( MountType.BIND, source=f"/var/.cagefs/website/{jail_utils.get_website_id(docroot)}", target="/var/.cagefs", ) generated_configs.append(jail_config.render(docroot)) return "\n".join(generated_configs) def write_jail_mounts_config(user: str, user_config: config.UserConfig | None) -> None: """ Write or remove the jail mounts configuration file for a user. If user_config is None or has no enabled websites, the config file is removed. Otherwise, builds and writes the mount configuration. Args: user: Username to generate config for user_config: User's isolation configuration, or None to remove config """ jail_config_path = Path(jail_utils.get_jail_config_path(user)) if user_config is None or not user_config.enabled_websites: jail_config_path.unlink(missing_ok=True) return builder = JailMountsConfigBuilder(user) try: domain_to_docroot_map = dict(userdomains(user)) except NoPanelUser: logging.warning("Cannot regenerate mount configuration, no panel user=%s", user) return # add docroot information for isolations for docroot in domain_to_docroot_map.values(): builder.add_docroot(docroot) # add information about which websites should have isolation enabled for domain in user_config.enabled_websites: try: docroot = domain_to_docroot_map[domain] except KeyError: logging.warning("Docroot not found for domain %s", domain) continue builder.enable_isolation(docroot) # PHP Selector is enabled for all isolated websites for domain in user_config.enabled_websites: try: docroot = domain_to_docroot_map[domain] except KeyError: logging.warning("Docroot not found for domain %s", domain) continue builder.enable_phpselector(docroot) result = builder.build() jail_config_path.parent.mkdir(exist_ok=True, mode=0o755) write_via_tmp(str(jail_config_path.parent), str(jail_config_path), result)