????
Current Path : /usr/local/ssl/share/cagefs/ |
Current File : //usr/local/ssl/share/cagefs/feature_manager.py |
#!/opt/cloudlinux/venv/bin/python3 -bb # # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2024 All Rights Reserved # # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENSE.TXT import argparse import enum import shutil import sys from dataclasses import dataclass from pathlib import Path from typing import Callable import logs from clflags.config import DEFAULT_FLAGS_STORAGE_PATH ENABLED_FEATURES_DIR = '/etc/cagefs/enabled_features' logger = logs.setup_logger('feature_manager', '/var/log/cloudlinux/cagefs.log') class FlagBehavior(enum.Enum): """ Defines the behavior of a CloudLinux Server Flag based on the presence of a file. The existence of this flag not only indicates that the 'feature' is enabled but could also mean it is explicitly disabled by creating the file. """ ENABLE_ON_PRESENT = enum.auto() DISABLE_ON_PRESENT = enum.auto() @dataclass class Flag: """ Represents a CloudLinux Server Flag typically located at /opt/cloudlinux/flags/enabled-flags.d/ with a specific behavior based on a file existence. """ flag_name: str flag_behavior: FlagBehavior @property def enabled(self) -> bool: flag_path = Path(DEFAULT_FLAGS_STORAGE_PATH, f'{self.flag_name}.flag') flag_exists = flag_path.exists() if self.flag_behavior == FlagBehavior.ENABLE_ON_PRESENT: return flag_exists elif self.flag_behavior == FlagBehavior.DISABLE_ON_PRESENT: return not flag_exists else: raise RuntimeError('Invalid value for the "flag_behavior" attribute') @dataclass class CageFsFeature: """ Represents a feature within the CageFS file system. """ name: str description: str handler: Callable flag: Flag @property def feature_marker_path(self) -> Path: """ Returns the path to the CageFS feature marker file. """ return Path(ENABLED_FEATURES_DIR, self.name) @property def enabled(self) -> bool: """ Determines if the CageFS feature is enabled based on the existence of its feature marker file and CloudLinux Server Flag status. """ return self.feature_marker_path.exists() and self.flag.enabled class CageFsFeatureManager: """ Manages a collection of CageFS features. """ def __init__(self, features: list[CageFsFeature]): self.features: list[CageFsFeature] = features def enable(self): for feature in self.features: self._enable_feature(feature) def sync(self): for feature in self.features: self._sync_feature(feature) def _enable_feature(self, feature: CageFsFeature): feature.feature_marker_path.touch() def _sync_feature(self, feature: CageFsFeature): feature.handler(feature.enabled) def handle_dbus_hardening(is_enabled: bool): """ Handles the hardening of D-Bus configuration based on the enabled state. Essentially, just copies/removes the config file to/from the appropriate place. """ config_name = 'cagefs-dbus-hardening.conf' local_path = Path('/usr/share/cagefs/configs/dbus', config_name) installed_path = Path('/etc/dbus-1/system.d', config_name) if is_enabled: if not installed_path.exists() and installed_path.parent.exists(): shutil.copy2(local_path, installed_path) else: installed_path.unlink(missing_ok=True) # List of available CageFS features FEATURES = [ CageFsFeature( name='dbus-hardening', description="Restrict user's capability to communicate " "with systemd via D-Bus using certain methods", handler=handle_dbus_hardening, flag=Flag( flag_name='disable-dbus-hardening', flag_behavior=FlagBehavior.DISABLE_ON_PRESENT, ), ), # ... Add new features here ... ] def enable(features: list[CageFsFeature]): """ Enable specified CageFS features. """ manager = CageFsFeatureManager(features) manager.enable() def sync(): """ Synchronize the state of CageFS featues based on their current enabled status. """ manager = CageFsFeatureManager(FEATURES) manager.sync() def main(): parser = argparse.ArgumentParser( description='Available manipulations with CageFS features') subparsers = parser.add_subparsers(dest='command', help='Available commands') # Enable command parser parser_enable = subparsers.add_parser('enable', help='Enable CageFS features') for feature in FEATURES: parser_enable.add_argument( f'--{feature.name}', action='store_true', help=feature.description, ) # Sync command parser subparsers.add_parser( 'sync', help='Sync CageFS features based on the state of the feature flags') args = parser.parse_args() try: match args.command: case 'enable': features = [feature for feature in FEATURES if getattr(args, feature.name.replace('-', '_'))] if not features: parser.error('At least one feature is required for the "enable" command') enable(features) case 'sync': sync() case _: parser.print_help() return 1 except Exception as e: logger.error('An error occurred during manipulations with CageFS features:', exc_info=e) return 1 if __name__ == '__main__': sys.exit(main())