fix: harden network security boundaries
CI / lint (pull_request) Successful in 33s
CI / sanitizers (address) (pull_request) Successful in 37s
CI / sanitizers (undefined) (pull_request) Successful in 37s
CI / fuzz-build (pull_request) Successful in 13s
CI / coverage (pull_request) Successful in 32s
CI / build-and-test (pull_request) Successful in 1m16s
CI / valgrind (pull_request) Successful in 32s

This commit is contained in:
2026-08-15 12:34:41 +02:00
parent 41b624db5a
commit ff189aeef2
11 changed files with 149 additions and 16 deletions
+23 -3
View File
@@ -23,6 +23,7 @@
static char* authorized_root;
static int authorized_root_fd = -1;
static bool allow_delete;
static bool allow_unauthenticated;
static bool path_is_within(const char* root, const char* path) {
size_t n = strlen(root);
@@ -34,6 +35,15 @@ static bool valid_batch_path(const char* path) {
strchr(path, '\0') == path + strlen(path);
}
static bool batch_path_exists_secure(const char* path, const char* root) {
char* full_path = path_cat(root, path);
if (!full_path)
return false;
bool exists = file_path_exists_secure(full_path);
free(full_path);
return exists;
}
static bool __attribute__((unused)) configure_authorization(const char* root) {
char resolved[PATH_MAX];
if (!root || !realpath(root, resolved))
@@ -121,7 +131,8 @@ int receive_files(Config* config, int fd) {
char* full_path = path_cat(config->receive_root_directory, check_path);
struct stat st;
bool has_old = full_path && lstat(full_path, &st) == 0;
bool match = has_old && (unsigned long long)st.st_size == check_size &&
bool secure_exists = batch_path_exists_secure(check_path, config->receive_root_directory);
bool match = has_old && secure_exists && (unsigned long long)st.st_size == check_size &&
(long long)st.st_mtime == check_mtime;
bool sent = send_status(fd, match ? STATUS_OK : STATUS_NEXT);
free(full_path);
@@ -179,6 +190,12 @@ void handler(int file_descriptor) {
close(file_descriptor);
return;
}
if (!allow_unauthenticated && ssl == NULL) {
log_message(LOG_LEVEL_ERROR, "Rejected unauthenticated plaintext connection");
config_delete(config);
close(file_descriptor);
return;
}
char resolved_destination[PATH_MAX];
char* canonical_destination = realpath(config->receive_root_directory, NULL);
const char* destination =
@@ -283,6 +300,7 @@ static void print_server_usage(void) {
printf(" --ca <path> TLS CA certificate file (PEM)\n");
printf(" --destination-root <path> Authorized destination root (default: .)\n");
printf(" --allow-delete Permit manifest deletion\n");
printf(" --allow-unauthenticated Allow plaintext/anonymous network clients\n");
printf(" -v, --verbose Enable debug logging\n");
printf(" --help Show this help\n");
}
@@ -317,6 +335,8 @@ int main(int argc, char* argv[]) {
destination_root = argv[++i];
} else if (strcmp(argv[i], "--allow-delete") == 0) {
allow_delete = true;
} else if (strcmp(argv[i], "--allow-unauthenticated") == 0) {
allow_unauthenticated = true;
} else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
char* end;
long p = strtol(argv[++i], &end, 10);
@@ -357,8 +377,8 @@ int main(int argc, char* argv[]) {
return 1;
}
if (use_tls) {
if (!tls_cert || !tls_key) {
fprintf(stderr, "Error: --tls requires --cert and --key\n");
if (!tls_cert || !tls_key || !tls_ca) {
fprintf(stderr, "Error: --tls requires --cert, --key, and --ca\n");
server_delete(&g_server);
return 1;
}