diff --git a/tcsfw/builder_backend.py b/tcsfw/builder_backend.py index 6601b2a..0b8e9a9 100644 --- a/tcsfw/builder_backend.py +++ b/tcsfw/builder_backend.py @@ -17,7 +17,7 @@ from tcsfw.batch_import import BatchImporter, LabelFilter from tcsfw.claim_coverage import RequirementClaimMapper from tcsfw.client_api import APIRequest, ClientPrompt -from tcsfw.components import CookieData, Cookies, DataReference, DataStorages, Software +from tcsfw.components import CookieData, Cookies, DataReference, DataStorages, OperatingSystem, Software from tcsfw.coverage_result import CoverageReport from tcsfw.entity import ClaimAuthority, Entity from tcsfw.event_interface import PropertyEvent @@ -26,7 +26,7 @@ from tcsfw.main import (ARP, DHCP, DNS, EAPOL, ICMP, NTP, SSH, HTTP, TCP, UDP, IP, TLS, BLEAdvertisement, ClaimBuilder, ClaimSetBuilder, ConnectionBuilder, CookieBuilder, HostBuilder, NodeBuilder, NodeVisualBuilder, - ConfigurationException, ProtocolConfigurer, ProtocolType, + ConfigurationException, OSBuilder, ProtocolConfigurer, ProtocolType, SensitiveDataBuilder, ServiceBuilder, ServiceGroupBuilder, ServiceOrGroup, SoftwareBuilder, SystemBuilder, VisualizerBuilder) from tcsfw.main_tools import EvidenceLoader, NodeManipulator, SubLoader, ToolPlanLoader @@ -379,6 +379,9 @@ def serve(self, *protocols: ProtocolType) -> Self: self / p # pylint: disable=pointless-statement return self + def os(self) -> OSBuilder: + return OSBackend(self) + def __lshift__(self, multicast: ServiceBackend) -> 'ConnectionBackend': mc = multicast.entity assert mc.is_multicast(), "Can only receive multicast" @@ -849,6 +852,15 @@ class ProtocolConfigurers: } +class OSBackend(OSBuilder): + """OS builder backend""" + def __init__(self, parent: HostBackend): + self.component = OperatingSystem.get_os(parent.entity) + + def processes(self, owner_process: Dict[str, List[str]]) -> 'OSBuilder': + self.component.process_map.update(owner_process) + + class ClaimBackend(ClaimBuilder): """Claim builder""" diff --git a/tcsfw/components.py b/tcsfw/components.py index df840f6..9fd8295 100644 --- a/tcsfw/components.py +++ b/tcsfw/components.py @@ -106,6 +106,23 @@ class SoftwareComponent: version: str = "" +class OperatingSystem(NodeComponent): + """Operating system""" + def __init__(self, entity: NetworkNode): + super().__init__(entity, "OS") + self.process_map: Dict[str, List[str]] = {} # owner: process names + + @classmethod + def get_os(cls, entity: NetworkNode) -> 'OperatingSystem': + """Get the OS for network node""" + for c in entity.components: + if isinstance(c, OperatingSystem): + return c + c = OperatingSystem(entity) + entity.components.append(c) + return c + + class DataStorages(NodeComponent): """Data storages in IoT system or network node""" def __init__(self, entity: NetworkNode, name="Sensitive data", data: List[SensitiveData] = None): diff --git a/tcsfw/main.py b/tcsfw/main.py index cbe6ee9..1793d4f 100644 --- a/tcsfw/main.py +++ b/tcsfw/main.py @@ -165,6 +165,10 @@ def use_data(self, *data: 'SensitiveDataBuilder') -> Self: """This host uses some sensitive data""" raise NotImplementedError() + def os(self) -> 'OSBuilder': + """Operating System definitions""" + raise NotImplementedError() + def __truediv__(self, protocol: ProtocolType) -> ServiceBuilder: """Pick or add the configured protocol""" raise NotImplementedError() @@ -353,6 +357,13 @@ def __init__(self, event_type: int): self.event_type = event_type +class OSBuilder: + """Operating System builder""" + def processes(self, owner_process: Dict[str, List[str]]) -> 'OSBuilder': + """Define processes: mapping from owner to list of processes""" + raise NotImplementedError() + + class ClaimBuilder: """Claim builder""" def key(self, *segments: str) -> Self: