fix(server): gate --force by --allow-delete and secure root super default
C2: --force is deletion authority (an incoming regular file may remove a non-empty destination directory tree, and --delete-missing-args may remove a non-empty directory mirror), but it was not masked by the operator --allow-delete policy. The handler now clears config->force_delete unless --allow-delete was given, exactly like --delete and --delete-missing-args. C3: a standalone TCP / --stdio server running as root defaulted to SUPER_MODE_AUTO, so an untrusted client --devices/--write-devices/ --super could make it create device nodes, write raw devices, or apply client-chosen ownership. A privileged standalone receiver now forces SUPER_MODE_OFF unless the operator opts in with the new server-only --allow-super flag. Non-root receivers are unchanged, and the daemon path keeps its per-module `client owner = yes` gate. --allow-super is rejected with --no-super or --daemon. C6: tls_client_identity_allowed now rejects a CN whose reported length reached the buffer bound, so a truncated over-long CN cannot be matched by a required --client-cn prefix. Tests: an integration regression proving --force cannot replace a destination directory without --allow-delete; standalone-default tests for --copy-as refusal and (root-only) skipped device creation; a CLI unit test for the new flag. The integration shared_server fixture opts in with --allow-super so the existing root-only ownership/device/copy-as tests continue to exercise the opted-in configuration. README and RSYNC_COMPAT document the flag and the force/delete gating.
This commit is contained in:
@@ -32,6 +32,28 @@ static void test_server_cli_defaults() {
|
||||
EXPECT_FALSE(opts.allow_delete);
|
||||
EXPECT_FALSE(opts.allow_unauthenticated);
|
||||
EXPECT_FALSE(opts.no_super);
|
||||
EXPECT_FALSE(opts.allow_super);
|
||||
server_cli_options_free(&opts);
|
||||
}
|
||||
|
||||
/* C3: --allow-super is the standalone/--stdio opt-in for a privileged receiver;
|
||||
* it never combines with --no-super, and daemon modules use their own per-module
|
||||
* `client owner = yes` opt-in instead. */
|
||||
static void test_server_cli_allow_super() {
|
||||
const char* args[] = {"fastsync-server", "--allow-super", "--destination-root", "/srv"};
|
||||
ServerCliOptions opts;
|
||||
EXPECT_EQ_INT(parse_ok(args, 4, &opts), 0);
|
||||
EXPECT_TRUE(opts.allow_super);
|
||||
server_cli_options_free(&opts);
|
||||
|
||||
char err[256];
|
||||
const char* a1[] = {"s", "--allow-super", "--no-super"};
|
||||
EXPECT_EQ_INT(server_cli_parse(3, (char**)a1, &opts, err, sizeof(err)), -1);
|
||||
EXPECT_TRUE(strstr(err, "mutually exclusive") != NULL);
|
||||
|
||||
const char* a2[] = {"s", "--daemon", "--config=/tmp/x.conf", "--allow-super"};
|
||||
EXPECT_EQ_INT(server_cli_parse(4, (char**)a2, &opts, err, sizeof(err)), -1);
|
||||
EXPECT_TRUE(strstr(err, "client owner") != NULL);
|
||||
server_cli_options_free(&opts);
|
||||
}
|
||||
|
||||
@@ -224,5 +246,6 @@ void test_server_cli() {
|
||||
test_server_cli_password_and_early_input();
|
||||
test_server_cli_password_requires_daemon();
|
||||
test_server_cli_no_super();
|
||||
test_server_cli_allow_super();
|
||||
test_server_cli_help();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user