#ifndef DAEMON_CONF_H #define DAEMON_CONF_H #include #include /* FastSync-native daemon configuration (a FastSync analog of rsyncd.conf). * * This is the config the fastsync-server --daemon listener consumes. It is * line-based with an implicit global section followed by zero or more * [module] sections. The full grammar is documented in RSYNC_COMPAT.md * ("Daemon Mode") and summarized below; the parser lives entirely in * daemon_conf.c so it can be unit tested without any socket code. * * The parser is STRICT: an unknown key, a malformed line, a value that does * not parse, a module without a `path`, or a line longer than * DAEMON_CONF_MAX_LINE all fail the whole load with a clear, line-numbered * error instead of being silently ignored. This keeps a typo from silently * changing what a module serves. */ /* A daemon module's configured root is used exactly like the standalone * server's --destination-root: the daemon confines every connection that * selects this module to this path (file_open_secure_parent / * has_path_traversal / path_is_within all keep the existing confinement, just * per-module). There is never any client-chosen root and no --super / * --copy-as: a module path always stays confined. * * `auth_users` is parsed and stored now (Wave A) for Wave B to honor, but the * presence of auth users is already enforced with a SAFE default this wave: * because FastSync cannot yet authenticate a claimed user, a module that * declares auth users refuses every connection (see server.c). Auth is never * bypassed by ignoring the list. */ typedef struct DaemonModule { char* name; /* module name, as the client requests it */ char* path; /* module root (daemon-side authorized root) */ bool read_only; /* `read only = yes/no`; default no */ char** auth_users; /* `auth users = a,b`; Wave B credential list */ int auth_user_count; } DaemonModule; /* Global (pre-module) scalar keys. `motd file` is parsed and stored but has * no wire effect yet (MOTD display is Wave C). */ typedef struct DaemonConfGlobals { int port; /* `port`, default DAEMON_CONF_DEFAULT_PORT (873) */ char* motd_file; /* `motd file`, may be NULL */ char* address; /* `address` (optional bind address), may be NULL */ } DaemonConfGlobals; typedef struct DaemonConf { DaemonConfGlobals global; DaemonModule* modules; int module_count; } DaemonConf; #define DAEMON_CONF_DEFAULT_PORT 873 /* Longest accepted config line (excluding the trailing newline). Longer lines * are rejected rather than buffered unboundedly. */ #define DAEMON_CONF_MAX_LINE 4096 /* Upper bound on a module name. Kept far below MAX_STRING_SIZE so a wire * module name can never exhaust anything by being long. */ #define DAEMON_MAX_MODULE_NAME 200 /* Allocate an empty daemon config with defaulted globals (port 873, no * modules, no motd/address). Never fails for an allocation failure; callers * must still NULL-check. */ DaemonConf* daemon_conf_create(void); /* Parse `path` into a freshly allocated DaemonConf. Returns NULL on any error * and fills `err` (err_size bytes) with a clear, line-numbered message. The * returned object is heap-owned; free it with daemon_conf_free. */ DaemonConf* daemon_conf_load(const char* path, char* err, size_t err_size); void daemon_conf_free(DaemonConf* conf); /* Case-sensitive exact module lookup by name. Returns the module or NULL. * Module names are matched exactly (rsync semantics). */ const DaemonModule* daemon_conf_find_module(const DaemonConf* conf, const char* name); /* Module-name syntax check: non-empty, at most DAEMON_MAX_MODULE_NAME chars, * and only [A-Za-z0-9._-]. Used by the config parser, the client's * host::module/path destination parser, and (implicitly) by the daemon lookup * (a name that fails this can never match a parsed module). */ bool daemon_module_name_valid(const char* name); /* Parse one --dparam=KEY=VALUE (or "--dparam KEY=VALUE") override string and * apply it to the global scalars only. Keys are case-insensitive and limited * to the global scalar keys defined by the grammar (port, motd file, address). * Returns 0 on success, -1 on error (err filled). */ int daemon_conf_apply_dparam(DaemonConf* conf, const char* assignment, char* err, size_t err_size); #endif