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
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:
+23
-3
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user