CMD packets arrive as unauthenticated UDP datagrams, yet every hbc client executed the shell command they carry without any opt-in. Add an allow_remote_command config key, default false: when off, the command is logged and refused with "Refused: allow_remote_command is false" (visible in the server event log under the command service), and subprocess is never reached. When on, the client warns at startup that it will execute CMD packets. Applied to all four clients that handle CMD — hbc, hbc_windows.py, hbc_mini.py, and the C hbc_mini — since gating only one leaves the others wide open. The C client reads the same key from ~/.hbc.json and needs a rebuild to pick it up. UPD (self-update) is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
65 lines
1.9 KiB
Python
65 lines
1.9 KiB
Python
"""Configuration loader and defaults for hbc (HeartBeat Client)."""
|
|
|
|
import logging
|
|
import os
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
|
import yaml
|
|
except Exception:
|
|
yaml = None
|
|
|
|
CLIENT_DEFAULTS = {
|
|
# Network settings
|
|
"hb_port": 50003, # Port where hbd servers listen
|
|
"interval": 10, # Heartbeat interval in seconds
|
|
|
|
# Host identity
|
|
"owner": None, # Optional username to set as this host's owner on the server
|
|
|
|
# Security
|
|
"allow_remote_command": False, # Execute shell commands received in CMD packets from the server
|
|
|
|
# Runtime flags
|
|
"foreground": False,
|
|
"verbose": False,
|
|
"debug": 0,
|
|
|
|
# Plugin configuration
|
|
"plugins": {}, # Per-plugin configuration
|
|
"thresholds": {}, # Threshold configuration for monitoring
|
|
}
|
|
|
|
|
|
def load_config(path=None):
|
|
"""Load configuration from a YAML file and merge with client defaults.
|
|
|
|
If YAML is not available or the file does not exist, defaults are returned.
|
|
|
|
Args:
|
|
path: Path to YAML config file (default: ~/.hbc.yaml)
|
|
|
|
Returns:
|
|
Dictionary with configuration
|
|
"""
|
|
cfg = CLIENT_DEFAULTS.copy()
|
|
if not path:
|
|
# default path (~/.hbc.yaml)
|
|
path = os.path.join(os.path.expanduser("~"), ".hbc.yaml")
|
|
|
|
if os.path.exists(path):
|
|
if yaml:
|
|
logger.info("Loading configuration from %s", path)
|
|
with open(path) as fh:
|
|
data = yaml.safe_load(fh)
|
|
# Merge YAML data with defaults
|
|
# Keep all keys from YAML to support plugin configs and future extensions
|
|
for k, v in data.items():
|
|
cfg[k] = v
|
|
else:
|
|
# yaml not installed: do not attempt to parse; user must ensure defaults
|
|
logger.warning("PyYAML not available - cannot load config from %s, using defaults", path)
|
|
return cfg
|