zscams 2.0.11__tar.gz → 2.0.13__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {zscams-2.0.11 → zscams-2.0.13}/PKG-INFO +1 -1
- {zscams-2.0.11 → zscams-2.0.13}/pyproject.toml +1 -1
- zscams-2.0.13/zscams/agent/configuration/freebsd_service.j2 +18 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/backend/bootstrap.py +11 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/backend/client.py +2 -5
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/services.py +2 -1
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/services/ssh_forwarder.py +0 -1
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/support/configuration.py +15 -8
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/support/os.py +32 -0
- zscams-2.0.13/zscams/agent/src/support/ssh.py +29 -0
- zscams-2.0.11/zscams/agent/configuration/freebsd_service.j2 +0 -20
- zscams-2.0.11/zscams/agent/src/support/ssh.py +0 -23
- {zscams-2.0.11 → zscams-2.0.13}/README.md +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/__init__.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/__main__.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/__init__.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/certificates/.gitkeep +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/configuration/config.j2 +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/configuration/linux_service.j2 +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/keys/autoport.key +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/__init__.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/__init__.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/backend/exceptions.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/backend/unbootstrap.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/backend/update_machine_info.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/prerequisites.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/service_health_check.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/tunnel/__init__.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/tunnel/tls.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/core/tunnels.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/services/__init__.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/services/reverse_ssh.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/services/system_monitor.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/support/__init__.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/support/cli.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/support/filesystem.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/support/logger.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/support/mac.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/support/network.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/support/openssl.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/agent/src/support/yaml.py +0 -0
- {zscams-2.0.11 → zscams-2.0.13}/zscams/deps.py +0 -0
|
@@ -3,7 +3,7 @@ name = "zscams_agent"
|
|
|
3
3
|
|
|
4
4
|
[tool.poetry]
|
|
5
5
|
name = "zscams"
|
|
6
|
-
version = "2.0.
|
|
6
|
+
version = "2.0.13"
|
|
7
7
|
description = "Async TLS tunnel client with SNI routing, auto-reconnect, and health checks"
|
|
8
8
|
authors = ["OCD - Cairo Software Team"]
|
|
9
9
|
maintainers = ["OCD - Cairo Software Team"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# PROVIDE: zscams
|
|
4
|
+
# REQUIRE: NETWORKING
|
|
5
|
+
# KEYWORD: shutdown
|
|
6
|
+
|
|
7
|
+
. /etc/rc.subr
|
|
8
|
+
|
|
9
|
+
name="zscams"
|
|
10
|
+
rcvar="zscams_enable"
|
|
11
|
+
|
|
12
|
+
command="/usr/sbin/daemon"
|
|
13
|
+
command_args="-f -p /var/run/${name}.pid -u {user_to_run_as} {python_exec} -m zscams"
|
|
14
|
+
|
|
15
|
+
pidfile="/var/run/${name}.pid"
|
|
16
|
+
|
|
17
|
+
load_rc_config $name
|
|
18
|
+
run_rc_command "$1"
|
|
@@ -10,6 +10,7 @@ from zscams.agent.src.support.os import (
|
|
|
10
10
|
install_service,
|
|
11
11
|
is_freebsd,
|
|
12
12
|
is_linux,
|
|
13
|
+
set_directory_ownership_and_permissions,
|
|
13
14
|
)
|
|
14
15
|
from zscams.agent.src.support.ssh import add_to_authorized_keys
|
|
15
16
|
from zscams.agent.src.support.cli import ensure_config_value, prompt, prompt_auth_info
|
|
@@ -76,6 +77,16 @@ def bootstrap():
|
|
|
76
77
|
create_system_user(sys_user)
|
|
77
78
|
add_to_authorized_keys(sys_user, cm_info.get("server_ssh_pub_key"))
|
|
78
79
|
install_zscams_systemd_service(sys_user)
|
|
80
|
+
set_dirs_permissions()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def set_dirs_permissions():
|
|
84
|
+
paths = [
|
|
85
|
+
ROOT_PATH.joinpath("certificates"),
|
|
86
|
+
ROOT_PATH.joinpath("keys"),
|
|
87
|
+
]
|
|
88
|
+
for path in paths:
|
|
89
|
+
set_directory_ownership_and_permissions(path, "zscams", 0o400)
|
|
79
90
|
|
|
80
91
|
|
|
81
92
|
def install_zscams_systemd_service(user_to_run_as: str):
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
-
from pathlib import Path
|
|
4
3
|
import requests
|
|
5
4
|
|
|
6
5
|
from typing import Optional, cast
|
|
@@ -184,16 +183,14 @@ class BackendClient:
|
|
|
184
183
|
|
|
185
184
|
def _write_certificates(self, ca_chain: list[str], cert: str):
|
|
186
185
|
if cert:
|
|
187
|
-
cert_path =
|
|
188
|
-
str(ROOT_PATH), self.remote_config.get("client_cert")
|
|
189
|
-
)
|
|
186
|
+
cert_path = ROOT_PATH.joinpath(self.remote_config.get("client_cert", ""))
|
|
190
187
|
|
|
191
188
|
self.logger.info("Writing signed certificate to %s", cert_path)
|
|
192
189
|
with open(cert_path, "w", encoding="utf-8") as cert_file:
|
|
193
190
|
cert_file.write(cert)
|
|
194
191
|
|
|
195
192
|
if ca_chain:
|
|
196
|
-
ca_chain_path =
|
|
193
|
+
ca_chain_path = ROOT_PATH.joinpath(self.remote_config.get("ca_chain", ""))
|
|
197
194
|
|
|
198
195
|
self.logger.info("Writing CA chain to %s", ca_chain_path)
|
|
199
196
|
with open(ca_chain_path, "w", encoding="utf-8") as ca_chain_file:
|
|
@@ -6,6 +6,7 @@ Service launcher utilities for TLS Tunnel Client
|
|
|
6
6
|
- Supports both Python scripts and executables
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
+
import sys
|
|
9
10
|
import asyncio
|
|
10
11
|
import json
|
|
11
12
|
import os
|
|
@@ -53,7 +54,7 @@ async def start_service(service_cfg, config_dir=None):
|
|
|
53
54
|
# Pass generic parameters to the service via JSON environment variable
|
|
54
55
|
env["SERVICE_PARAMS"] = json.dumps(params)
|
|
55
56
|
|
|
56
|
-
cmd = [
|
|
57
|
+
cmd = [sys.executable, script_path] + service_cfg.get("args", [])
|
|
57
58
|
logger.info(
|
|
58
59
|
"Starting service %s on port %d: %s",
|
|
59
60
|
service_cfg.get("name"),
|
|
@@ -3,8 +3,9 @@ Configuration loader module
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
+
import shutil
|
|
6
7
|
from pathlib import Path
|
|
7
|
-
from typing import Optional, Type, TypedDict, cast
|
|
8
|
+
from typing import Optional, Type, TypeVar, TypedDict, cast
|
|
8
9
|
import yaml
|
|
9
10
|
|
|
10
11
|
import zscams
|
|
@@ -13,6 +14,8 @@ from zscams.agent.src.support.yaml import YamlIndentedListsDumper, resolve_place
|
|
|
13
14
|
ROOT_PATH = Path(zscams.__file__).resolve().parent.joinpath("agent")
|
|
14
15
|
CONFIG_PATH = os.path.join(ROOT_PATH.absolute(), "config.yaml")
|
|
15
16
|
|
|
17
|
+
GetReturnT = TypeVar("GetReturnT")
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
class MissingConfiguration(BaseException):
|
|
18
21
|
"""Error when the requisted key is not found"""
|
|
@@ -33,8 +36,12 @@ class Configuration:
|
|
|
33
36
|
return cls.__instance
|
|
34
37
|
|
|
35
38
|
def __load_config(self):
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
try:
|
|
40
|
+
with open(CONFIG_PATH, "r", encoding="utf-8") as f:
|
|
41
|
+
self.__config = yaml.safe_load(f)
|
|
42
|
+
except FileNotFoundError:
|
|
43
|
+
shutil.copyfile(ROOT_PATH.joinpath("configuration/config.j2"), CONFIG_PATH)
|
|
44
|
+
self.__load_config()
|
|
38
45
|
|
|
39
46
|
def override_config(self, new_config: dict):
|
|
40
47
|
"""
|
|
@@ -56,13 +63,13 @@ class Configuration:
|
|
|
56
63
|
def to_dict(self):
|
|
57
64
|
return self.__config
|
|
58
65
|
|
|
59
|
-
def get
|
|
66
|
+
def get(
|
|
60
67
|
self,
|
|
61
68
|
key: str,
|
|
62
|
-
default: Optional[
|
|
69
|
+
default: Optional[GetReturnT] = None,
|
|
63
70
|
must_resolve=False,
|
|
64
|
-
valtyp: Type[
|
|
65
|
-
) ->
|
|
71
|
+
valtyp: Type[GetReturnT] = str,
|
|
72
|
+
) -> GetReturnT:
|
|
66
73
|
"""
|
|
67
74
|
Returns the configuration value.
|
|
68
75
|
|
|
@@ -90,7 +97,7 @@ class Configuration:
|
|
|
90
97
|
val = None
|
|
91
98
|
break
|
|
92
99
|
|
|
93
|
-
return cast(
|
|
100
|
+
return cast(GetReturnT, val)
|
|
94
101
|
|
|
95
102
|
def has(self, key: str):
|
|
96
103
|
try:
|
|
@@ -3,6 +3,7 @@ from pathlib import Path
|
|
|
3
3
|
import sys
|
|
4
4
|
import subprocess
|
|
5
5
|
import platform
|
|
6
|
+
from typing import Optional
|
|
6
7
|
from zscams.agent.src.support.logger import get_logger
|
|
7
8
|
from zscams.agent.src.support.mac import get_mac_address
|
|
8
9
|
|
|
@@ -22,6 +23,37 @@ def is_freebsd():
|
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
|
|
26
|
+
def set_directory_ownership_and_permissions(
|
|
27
|
+
directory_path: str | Path,
|
|
28
|
+
owner_user: Optional[str] = None,
|
|
29
|
+
mod: Optional[int] = None,
|
|
30
|
+
):
|
|
31
|
+
if not is_linux() and not is_freebsd():
|
|
32
|
+
logger.error("Unsupported OS to change directory owner or mod.")
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
if not owner_user and not mod:
|
|
36
|
+
raise ValueError("You have to provide a user or mod")
|
|
37
|
+
|
|
38
|
+
for root, _dirs, files in os.walk(directory_path):
|
|
39
|
+
if owner_user:
|
|
40
|
+
os.chown(root, owner_user)
|
|
41
|
+
if mod:
|
|
42
|
+
os.chmod(root, mod)
|
|
43
|
+
|
|
44
|
+
for name in files:
|
|
45
|
+
file_path = os.path.join(root, name)
|
|
46
|
+
if owner_user:
|
|
47
|
+
os.chown(file_path, owner_user)
|
|
48
|
+
if mod:
|
|
49
|
+
os.chmod(file_path, mod)
|
|
50
|
+
|
|
51
|
+
if owner_user:
|
|
52
|
+
os.chown(directory_path, owner_user)
|
|
53
|
+
if mod:
|
|
54
|
+
os.chmod(directory_path, mod)
|
|
55
|
+
|
|
56
|
+
|
|
25
57
|
def system_user_exists(username: str):
|
|
26
58
|
try:
|
|
27
59
|
subprocess.run(
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from zscams.agent.src.support.filesystem import append_to_file
|
|
2
|
+
from zscams.agent.src.support.logger import get_logger
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
logger = get_logger("ssh_support")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def add_to_known_hosts(user: str, hostname: str, pub_key: str):
|
|
9
|
+
try:
|
|
10
|
+
logger.debug("Appending '%s' to known hosts...", pub_key)
|
|
11
|
+
append_to_file(
|
|
12
|
+
f"/home/{user}/.ssh/known_hosts",
|
|
13
|
+
f"{hostname} {pub_key}\n",
|
|
14
|
+
)
|
|
15
|
+
logger.debug("Appended key to known hosts")
|
|
16
|
+
except:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def add_to_authorized_keys(user: str, pub_key: str):
|
|
21
|
+
logger.debug(f"Appending to public key to {user}")
|
|
22
|
+
key = pub_key.split(" ")[1] if len(pub_key.split(" ")) >= 2 else pub_key
|
|
23
|
+
try:
|
|
24
|
+
append_to_file(
|
|
25
|
+
f"/home/{user}/.ssh/authorized_keys",
|
|
26
|
+
f"ssh-rsa {key} zscams@orangecyberdefense\n",
|
|
27
|
+
)
|
|
28
|
+
except:
|
|
29
|
+
pass
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
|
|
3
|
-
# PROVIDE: zscams
|
|
4
|
-
# REQUIRE: NETWORKING
|
|
5
|
-
# KEYWORD: shutdown
|
|
6
|
-
|
|
7
|
-
. /etc/rc.subr
|
|
8
|
-
|
|
9
|
-
name="zscams"
|
|
10
|
-
rcvar="zscams_enable"
|
|
11
|
-
|
|
12
|
-
# Execution command and arguments
|
|
13
|
-
command="{python_exec}"
|
|
14
|
-
command_args="-m zscams"
|
|
15
|
-
|
|
16
|
-
# User to run the process
|
|
17
|
-
zscams_user="{user_to_run_as}"
|
|
18
|
-
|
|
19
|
-
load_rc_config $name
|
|
20
|
-
run_rc_command "$1"
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
from zscams.agent.src.support.filesystem import append_to_file
|
|
2
|
-
from zscams.agent.src.support.logger import get_logger
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
logger = get_logger("ssh_support")
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def add_to_known_hosts(user: str, hostname: str, pub_key: str):
|
|
9
|
-
logger.debug("Appending '%s' to known hosts...", pub_key)
|
|
10
|
-
append_to_file(
|
|
11
|
-
f"/home/{user}/.ssh/known_hosts",
|
|
12
|
-
f"{hostname} {pub_key}\n",
|
|
13
|
-
)
|
|
14
|
-
logger.debug("Appended key to known hosts")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def add_to_authorized_keys(user: str, pub_key: str):
|
|
18
|
-
logger.debug(f"Appending to public key to {user}")
|
|
19
|
-
key = pub_key.split(" ")[1] if len(pub_key.split(" ")) >= 2 else pub_key
|
|
20
|
-
append_to_file(
|
|
21
|
-
f"/home/{user}/.ssh/authorized_keys",
|
|
22
|
-
f"ssh-rsa {key} zscams@orangecyberdefense\n",
|
|
23
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|