refactor: drop dead filter_rules_apply, unify set_error, dedup path_is_within

This commit is contained in:
2026-09-21 21:09:05 +02:00
parent 0669335ca5
commit 134dcd74cc
9 changed files with 37 additions and 63 deletions
+1 -6
View File
@@ -226,11 +226,6 @@ static void release_authorization(void) {
close(root_fd);
}
static bool path_is_within(const char* root, const char* path) {
size_t n = strlen(root);
return strncmp(root, path, n) == 0 && (path[n] == '\0' || path[n] == '/');
}
/* --mkpath contract: when the client's destination root directory does not
exist yet on the server side, --mkpath tells the server to create it (and
any missing leading components) below the authorized root at connection
@@ -790,7 +785,7 @@ void handler(int file_descriptor) {
if (joined_destination)
destination = joined_destination;
if (!destination || has_path_traversal(destination) ||
!path_is_within(authorized_root, destination)) {
!path_is_within_root(authorized_root, destination)) {
log_message(LOG_LEVEL_ERROR, "Rejected destination outside authorized root");
free(joined_destination);
joined_destination = NULL;
+1 -9
View File
@@ -3,20 +3,12 @@
#include "credentials.h"
#include "utils.h"
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
static void set_error(char* err, size_t err_size, const char* fmt, ...) {
if (!err || err_size == 0)
return;
va_list args;
va_start(args, fmt);
vsnprintf(err, err_size, fmt, args);
va_end(args);
}
#define set_error utils_set_error
void server_cli_options_default(ServerCliOptions* opts) {
if (!opts)
+1 -9
View File
@@ -8,7 +8,6 @@
#include <openssl/evp.h>
#include <openssl/params.h>
#include <openssl/rand.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -58,14 +57,7 @@ struct CredentialStore {
static const uint8_t k_dummy_stored_key[CREDENTIAL_KEY_LEN] = {0};
static const uint8_t k_dummy_server_key[CREDENTIAL_KEY_LEN] = {0};
static void set_error(char* err, size_t err_size, const char* fmt, ...) {
if (!err || err_size == 0)
return;
va_list args;
va_start(args, fmt);
vsnprintf(err, err_size, fmt, args);
va_end(args);
}
#define set_error utils_set_error
static bool is_comment_char(char c) {
return c == '#' || c == ';';
+1 -9
View File
@@ -6,7 +6,6 @@
#include <errno.h>
#include <limits.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -17,14 +16,7 @@
/* helpers */
/* ------------------------------------------------------------------ */
static void set_error(char* err, size_t err_size, const char* fmt, ...) {
if (!err || err_size == 0)
return;
va_list args;
va_start(args, fmt);
vsnprintf(err, err_size, fmt, args);
va_end(args);
}
#define set_error utils_set_error
/* Trim leading and trailing ASCII space/tab in place; returns the new start. */
static char* trim_ws(char* s) {
+2 -17
View File
@@ -4,22 +4,12 @@
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Write a diagnostic message into the caller's optional buffer. A NULL `err`
* (or a zero size) is a no-op, so a caller that only needs the boolean status
* may pass NULL without the snprintf-on-NULL undefined behaviour. */
static void filter_set_error(char* err, size_t err_size, const char* fmt, ...) {
if (!err || err_size == 0)
return;
va_list ap;
va_start(ap, fmt);
vsnprintf(err, err_size, fmt, ap);
va_end(ap);
}
/* Write a diagnostic message into the caller's optional buffer. */
#define filter_set_error utils_set_error
/* ---- Ordered rule lists ---- */
@@ -870,8 +860,3 @@ FilterAction filter_rules_apply_side(const FilterRuleList* list, const char* rel
}
return FILTER_ACTION_NONE;
}
FilterAction filter_rules_apply(const FilterRuleList* list, const char* rel_path, const char* leaf,
bool is_dir) {
return filter_rules_apply_side(list, rel_path, leaf, is_dir, FILTER_SIDE_SENDER);
}
-5
View File
@@ -131,9 +131,4 @@ FilterRuleList* filter_file_read(const char* dir_path, const char* owner_rel, bo
FilterAction filter_rules_apply_side(const FilterRuleList* list, const char* rel_path,
const char* leaf, bool is_dir, unsigned side);
/* Sender-side convenience wrapper (kept for callers/tests that only need the
* transfer decision). */
FilterAction filter_rules_apply(const FilterRuleList* list, const char* rel_path, const char* leaf,
bool is_dir);
#endif
+10
View File
@@ -7,6 +7,7 @@
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -48,6 +49,15 @@ const char* utils_get_authorized_root_path(void) {
return authorized_root_path;
}
void utils_set_error(char* err, size_t err_size, const char* fmt, ...) {
if (!err || err_size == 0)
return;
va_list args;
va_start(args, fmt);
vsnprintf(err, err_size, fmt, args);
va_end(args);
}
bool path_is_within_root(const char* root, const char* path) {
size_t root_len = strlen(root);
return strncmp(root, path, root_len) == 0 && (path[root_len] == '\0' || path[root_len] == '/');
+5
View File
@@ -225,6 +225,11 @@ void utils_set_authorized_root_fd(int fd);
* threads spawn; see utils.c). */
int utils_get_authorized_root_fd(void);
const char* utils_get_authorized_root_path(void);
/* Write a diagnostic message into a caller-supplied buffer, mirroring
* vsnprintf. A NULL `err` or a zero `err_size` is a no-op, so a caller that
* only needs the boolean status may safely pass NULL. Returns nothing; the
* buffer is always NUL-terminated by vsnprintf when err_size > 0. */
void utils_set_error(char* err, size_t err_size, const char* fmt, ...);
/* True when `path` is `root` itself or lies directly beneath it: a lexical
* prefix test requiring the byte after `root` to be '\0' or '/'. Both `root`
* and `path` must be absolute canonical paths free of "."/".." components (the
+16 -8
View File
@@ -179,8 +179,10 @@ static void test_filter_rules_apply_supported_modifiers() {
const char* texts[] = {"- *.tmp"};
FilterRuleList* list = filter_base_build(texts, 1, false, false, NULL, 0);
EXPECT_NOT_NULL(list);
EXPECT_EQ_INT(filter_rules_apply(list, "b.tmp", "b.tmp", false), FILTER_ACTION_EXCLUDE);
EXPECT_EQ_INT(filter_rules_apply(list, "a.txt", "a.txt", false), FILTER_ACTION_NONE);
EXPECT_EQ_INT(filter_rules_apply_side(list, "b.tmp", "b.tmp", false, FILTER_SIDE_SENDER),
FILTER_ACTION_EXCLUDE);
EXPECT_EQ_INT(filter_rules_apply_side(list, "a.txt", "a.txt", false, FILTER_SIDE_SENDER),
FILTER_ACTION_NONE);
filter_rule_list_free(list);
}
/* anchored include then exclude-all */
@@ -188,8 +190,10 @@ static void test_filter_rules_apply_supported_modifiers() {
const char* texts[] = {"+ /a.txt", "- *"};
FilterRuleList* list = filter_base_build(texts, 2, false, false, NULL, 0);
EXPECT_NOT_NULL(list);
EXPECT_EQ_INT(filter_rules_apply(list, "a.txt", "a.txt", false), FILTER_ACTION_INCLUDE);
EXPECT_EQ_INT(filter_rules_apply(list, "b.txt", "b.txt", false), FILTER_ACTION_EXCLUDE);
EXPECT_EQ_INT(filter_rules_apply_side(list, "a.txt", "a.txt", false, FILTER_SIDE_SENDER),
FILTER_ACTION_INCLUDE);
EXPECT_EQ_INT(filter_rules_apply_side(list, "b.txt", "b.txt", false, FILTER_SIDE_SENDER),
FILTER_ACTION_EXCLUDE);
filter_rule_list_free(list);
}
/* negate */
@@ -197,8 +201,10 @@ static void test_filter_rules_apply_supported_modifiers() {
const char* texts[] = {"-! *.o"};
FilterRuleList* list = filter_base_build(texts, 1, false, false, NULL, 0);
EXPECT_NOT_NULL(list);
EXPECT_EQ_INT(filter_rules_apply(list, "foo.c", "foo.c", false), FILTER_ACTION_EXCLUDE);
EXPECT_EQ_INT(filter_rules_apply(list, "foo.o", "foo.o", false), FILTER_ACTION_NONE);
EXPECT_EQ_INT(filter_rules_apply_side(list, "foo.c", "foo.c", false, FILTER_SIDE_SENDER),
FILTER_ACTION_EXCLUDE);
EXPECT_EQ_INT(filter_rules_apply_side(list, "foo.o", "foo.o", false, FILTER_SIDE_SENDER),
FILTER_ACTION_NONE);
filter_rule_list_free(list);
}
/* dir-only trailing slash */
@@ -206,8 +212,10 @@ static void test_filter_rules_apply_supported_modifiers() {
const char* texts[] = {"+ dir/", "- *"};
FilterRuleList* list = filter_base_build(texts, 2, false, false, NULL, 0);
EXPECT_NOT_NULL(list);
EXPECT_EQ_INT(filter_rules_apply(list, "dir", "dir", true), FILTER_ACTION_INCLUDE);
EXPECT_EQ_INT(filter_rules_apply(list, "dir", "dir", false), FILTER_ACTION_EXCLUDE);
EXPECT_EQ_INT(filter_rules_apply_side(list, "dir", "dir", true, FILTER_SIDE_SENDER),
FILTER_ACTION_INCLUDE);
EXPECT_EQ_INT(filter_rules_apply_side(list, "dir", "dir", false, FILTER_SIDE_SENDER),
FILTER_ACTION_EXCLUDE);
filter_rule_list_free(list);
}
}