fix(d5-daemon-core): cppcheck const-correctness, wire module length cap, daemonize chdir/umask, daemon confinement tests
- daemon_conf.c/server.c/test_daemon_conf.c: const-qualify parse/loop pointers; scope user_path static inside its block (clears the 9-wave-A cppcheck findings) - config.c receive_daemon_module: reject invalid/over-long wire module names (> DAEMON_MAX_MODULE_NAME) with a clean STATUS_ERROR; client side already enforced via daemon_module_name_valid in config_parse_daemon_dest - server.c daemonize: chdir(/) and umask(0) so module paths resolve from / and config-requested file modes are honored; PROTOCOL_VERSION stays 2.15.0 - test_daemon.py: confinement (read-only/unknown no-write anywhere), module-less and dot-dot destination refusal, real daemon_detach double-fork path
This commit is contained in:
+9
-1
@@ -19,6 +19,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
static char* authorized_root;
|
||||
@@ -459,9 +461,9 @@ static void print_server_usage(void) {
|
||||
* exists (or when HOME is set), otherwise /etc/fastsyncd.conf. Returns a
|
||||
* pointer to a static buffer (never NULL). */
|
||||
static const char* default_daemon_config_path(void) {
|
||||
static char user_path[PATH_MAX];
|
||||
const char* home = getenv("HOME");
|
||||
if (home && *home) {
|
||||
static char user_path[PATH_MAX];
|
||||
int n = snprintf(user_path, sizeof(user_path), "%s/.config/fastsync/fastsyncd.conf", home);
|
||||
if (n > 0 && (size_t)n < sizeof(user_path) && access(user_path, R_OK) == 0)
|
||||
return user_path;
|
||||
@@ -496,6 +498,12 @@ static bool daemonize(void) {
|
||||
if (devnull > STDERR_FILENO)
|
||||
close(devnull);
|
||||
}
|
||||
/* Do not pin the launch CWD (module-relative 'path' entries would resolve
|
||||
* against an unstable working directory) and drop the restrictive host umask
|
||||
* so modules can create files/dirs with the modes the config requests. */
|
||||
if (chdir("/") != 0)
|
||||
log_message(LOG_LEVEL_WARNING, "daemon: chdir to / failed: %s", strerror(errno));
|
||||
umask(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1070,6 +1070,16 @@ static bool receive_daemon_module(int fd, Config* c) {
|
||||
char* module = receive_str(fd);
|
||||
if (!module)
|
||||
return false;
|
||||
/* Guard against a hostile client flooding the log with an over-long module
|
||||
* name: only an empty string (module-less) or a valid module name
|
||||
* (bounded by DAEMON_MAX_MODULE_NAME) is accepted. This is an input
|
||||
* guard, not a wire-format change. */
|
||||
if (*module != '\0' && !daemon_module_name_valid(module)) {
|
||||
log_message(LOG_LEVEL_WARNING, "Daemon client sent an invalid or over-long module name");
|
||||
free(module);
|
||||
send_status(fd, STATUS_ERROR);
|
||||
return false;
|
||||
}
|
||||
if (*module != '\0') {
|
||||
c->module = module;
|
||||
} else {
|
||||
|
||||
@@ -122,7 +122,8 @@ static bool store_port(int* slot, const char* value, char* err, size_t err_size)
|
||||
|
||||
/* Apply a global scalar key/value. Keys are case-insensitive. Returns false
|
||||
* (err filled) on an unknown key or an invalid value. */
|
||||
static bool apply_global_key(DaemonConf* conf, char* key, char* value, char* err, size_t err_size) {
|
||||
static bool apply_global_key(DaemonConf* conf, char* key, const char* value, char* err,
|
||||
size_t err_size) {
|
||||
if (key_equals(key, "port"))
|
||||
return store_port(&conf->global.port, value, err, err_size);
|
||||
if (key_equals(key, "motd file")) {
|
||||
@@ -177,7 +178,7 @@ static bool apply_module_key(DaemonModule* module, char* key, char* value, char*
|
||||
}
|
||||
char* save = NULL;
|
||||
for (char* token = strtok_r(list, ",", &save); token; token = strtok_r(NULL, ",", &save)) {
|
||||
char* user = trim_ws(token);
|
||||
const char* user = trim_ws(token);
|
||||
if (*user == '\0')
|
||||
continue;
|
||||
char** grown =
|
||||
@@ -341,7 +342,7 @@ DaemonConf* daemon_conf_load(const char* path, char* err, size_t err_size) {
|
||||
}
|
||||
*close = '\0';
|
||||
char* trailing = close + 1;
|
||||
char* rest = trim_ws(trailing);
|
||||
const char* rest = trim_ws(trailing);
|
||||
if (*rest != '\0') {
|
||||
set_error(err, err_size, "line %d: unexpected text after module header", line_no);
|
||||
ok = false;
|
||||
@@ -425,7 +426,7 @@ int daemon_conf_apply_dparam(DaemonConf* conf, const char* assignment, char* err
|
||||
}
|
||||
*eq = '\0';
|
||||
char* key = trim_ws(copy);
|
||||
char* value = trim_ws(eq + 1);
|
||||
const char* value = trim_ws(eq + 1);
|
||||
if (*key == '\0') {
|
||||
free(copy);
|
||||
set_error(err, err_size, "--dparam '%s' has an empty key", assignment);
|
||||
|
||||
Reference in New Issue
Block a user