diff --git a/dissect/target/plugins/os/unix/_os.py b/dissect/target/plugins/os/unix/_os.py index 5979ecdd8..5a0017b77 100644 --- a/dissect/target/plugins/os/unix/_os.py +++ b/dissect/target/plugins/os/unix/_os.py @@ -132,28 +132,46 @@ def domain(self) -> Optional[str]: def os(self) -> str: return OperatingSystem.UNIX.value + def _parse_rh_legacy(self, path): + hostname = None + file_contents = path.open("rt").readlines() + for line in file_contents: + if not line.startswith("HOSTNAME"): + continue + _, _, hostname = line.rstrip().partition("=") + return hostname + def _parse_hostname_string(self, paths: Optional[list[str]] = None) -> Optional[dict[str, str]]: """ - Returns a dict with containing the hostname and domain name portion of the path(s) specified + Returns a dict containing the hostname and domain name portion of the path(s) specified Args: paths (list): list of paths """ - paths = paths or ["/etc/hostname", "/etc/HOSTNAME"] - hostname_string = None + redhat_legacy_path = "/etc/sysconfig/network" + paths = paths or ["/etc/hostname", "/etc/HOSTNAME", redhat_legacy_path] + hostname_dict = {"hostname": None, "domain": None} for path in paths: - for fs in self.target.filesystems: - if fs.exists(path): - hostname_string = fs.path(path).open("rt").read().rstrip() + path = self.target.fs.path(path) + + if not path.exists(): + continue + + if path.as_posix() == redhat_legacy_path: + hostname_string = self._parse_rh_legacy(path) + else: + hostname_string = path.open("rt").read().rstrip() if hostname_string and "." in hostname_string: hostname_string = hostname_string.split(".", maxsplit=1) hostname_dict = {"hostname": hostname_string[0], "domain": hostname_string[1]} - else: + elif hostname_string != "": hostname_dict = {"hostname": hostname_string, "domain": None} - - return hostname_dict + else: + hostname_dict = {"hostname": None, "domain": None} + break # break whenever a valid hostname is found + return hostname_dict def _parse_hosts_string(self, paths: Optional[list[str]] = None) -> dict[str, str]: paths = paths or ["/etc/hosts"] diff --git a/tests/plugins/os/unix/test__os.py b/tests/plugins/os/unix/test__os.py index 087681ccd..c727d78ed 100644 --- a/tests/plugins/os/unix/test__os.py +++ b/tests/plugins/os/unix/test__os.py @@ -1,8 +1,13 @@ import tempfile +from io import BytesIO +from pathlib import Path from uuid import UUID +import pytest + from dissect.target.filesystem import VirtualFilesystem from dissect.target.plugins.os.unix._os import parse_fstab +from dissect.target.target import Target FSTAB_CONTENT = """ # /etc/fstab: static file system information. @@ -61,3 +66,37 @@ def test_parse_fstab(tmp_path): (None, "vg--main-lv--var", "/var", "auto", "default"), (None, "vg--main-lv--data", "/data", "auto", "default"), } + + +@pytest.mark.parametrize( + "path, expected_hostname, expected_domain, file_content", + [ + ("/etc/hostname", "myhost", "mydomain.com", "myhost.mydomain.com"), + ("/etc/HOSTNAME", "myhost", "mydomain.com", "myhost.mydomain.com"), + ( + "/etc/sysconfig/network", + "myhost", + "mydomain.com", + "NETWORKING=NO\nHOSTNAME=myhost.mydomain.com\nGATEWAY=192.168.1.1", + ), + ("/etc/hostname", "myhost", None, "myhost"), + ("/etc/sysconfig/network", "myhost", None, "NETWORKING=NO\nHOSTNAME=myhost\nGATEWAY=192.168.1.1"), + ("/not_a_valid_hostname_path", None, None, ""), + ("/etc/hostname", None, None, ""), + ("/etc/sysconfig/network", None, None, ""), + ], +) +def test__parse_hostname_string( + target_unix: Target, + fs_unix: VirtualFilesystem, + path: Path, + expected_hostname: str, + expected_domain: str, + file_content: str, +) -> None: + fs_unix.map_file_fh(path, BytesIO(file_content.encode("ascii"))) + + hostname_dict = target_unix._os._parse_hostname_string() + + assert hostname_dict["hostname"] == expected_hostname + assert hostname_dict["domain"] == expected_domain