D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
cloudlinux
/
venv
/
lib
/
python3.11
/
site-packages
/
clcagefslib
/
webisolation
/
Filename :
jail_utils.py
back
Copy
# -*- 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/LICENCE.TXT # import os import pathlib import secrets import shutil from pathlib import Path from clcommon import ClPwd from clcommon.clpwd import drop_privileges from clcagefslib.fs import get_user_var_cagefs_path from clcagefslib.io import write_via_tmp # FNV-1a 64-bit hash constants (must match jail C implementation) _FNV_OFFSET_BASIS = 14695981039346656037 _FNV_PRIME = 1099511628211 def get_jail_config_path(user): cagefs_dir = get_user_var_cagefs_path(user) return pathlib.Path(f"{cagefs_dir}/.cagefs/isolates.mounts") def get_website_id(document_root: str): """ Generates unique id for an isolate website using FNV-1a 64-bit hash. FNV-1a has excellent avalanche properties and distribution. Must match the docroot_hash() function in jail C code. """ hash_value = _FNV_OFFSET_BASIS for char in document_root.encode("utf-8"): hash_value ^= char hash_value = (hash_value * _FNV_PRIME) & 0xFFFFFFFFFFFFFFFF # Keep 64-bit return f"{hash_value:016x}" def create_website_token_directory(user: str, document_root: str): """ Create website token directory structure and files in /var/cagefs. Creates: - /var/cagefs/<user>/.cagefs/website/<website_id>/ - token directory """ pw = ClPwd().get_pw_by_name(user) website_id = get_website_id(document_root) # Token directory in /var/cagefs website_base_dir = Path(get_user_var_cagefs_path(user)) / ".cagefs/website" website_dir = website_base_dir / website_id # mode to prevent directory listing by other users website_base_dir.mkdir(exist_ok=True, parents=True, mode=0o751) # mode to allow user list /var/.cagefs when it's mounted for website website_dir.mkdir(exist_ok=True, mode=0o755) token = _generate_password(32) # create token file read-only for owner, others cannot read it # this replicates behavior of regular token # note: user can still use chown to change it token_file_path = f"{website_dir}/.cagefs.token" write_via_tmp(website_dir, token_file_path, token) os.chmod(token_file_path, 0o400) os.chown(token_file_path, pw.pw_uid, 0) # create file with document root path # that we can use as trusted source in proxyexec docroot_file_path = f"{website_dir}/.cagefs.website" write_via_tmp(website_dir, docroot_file_path, document_root) # only read permissions, without modification # we use this marker as a trusted source of document root # it should not be modifiable by user in any way os.chmod(docroot_file_path, 0o444) os.chown(docroot_file_path, 0, 0) def create_overlay_storage_directory(user: str, document_root: str): """ Create overlay storage directory in user's home. Creates: - <homedir>/.cagefs/websites/<website_id>/ - storage base for overlays Drops privileges to user before creating to ensure proper ownership. """ pw = ClPwd().get_pw_by_name(user) if not Path(pw.pw_dir).exists(): return storage_base = Path(full_website_path(pw.pw_dir, document_root)) with drop_privileges(user): storage_base.mkdir(exist_ok=True, parents=True, mode=0o750) def remove_website_token_directory(user: str, document_root: str): """ Remove website token directory structure and files. """ website_base_dir = Path(get_user_var_cagefs_path(user)) / ".cagefs/website" website_dir = website_base_dir / get_website_id(document_root) if website_dir.exists(): shutil.rmtree(website_dir) def website_suffix_with_hash(docroot): """ Returns path: websites/<document_root_hash> """ return os.path.join("websites", get_website_id(docroot)) def full_website_path(homedir, docroot): """ Returns <homedir>/.cagefs/websites/<document_root_hash> """ return os.path.join(homedir, ".cagefs", website_suffix_with_hash(docroot)) def invalidate_ns_cache(user: str, document_root: str): """ Removes cached namespace from disk """ website_base_dir = Path(get_user_var_cagefs_path(user)) / ".cagefs/website" website_dir = website_base_dir / get_website_id(document_root) (website_dir / ".cagefs.mnt").unlink(missing_ok=True) def _generate_password(length): """ Generate a random password/token using the same algorithm as the C function. Uses cryptographically secure random bytes and converts them to alphanumeric characters. """ if length == 0 or length > 256: raise ValueError("Invalid buffer length requested") charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" charset_size = len(charset) # Generate random bytes random_bytes = secrets.token_bytes(length) # Convert bytes to alphanumeric characters result = "".join(charset[b % charset_size] for b in random_bytes) return result