refactor: drop dead filter_rules_apply, unify set_error, dedup path_is_within
This commit is contained in:
+1
-6
@@ -226,11 +226,6 @@ static void release_authorization(void) {
|
|||||||
close(root_fd);
|
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
|
/* --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
|
exist yet on the server side, --mkpath tells the server to create it (and
|
||||||
any missing leading components) below the authorized root at connection
|
any missing leading components) below the authorized root at connection
|
||||||
@@ -790,7 +785,7 @@ void handler(int file_descriptor) {
|
|||||||
if (joined_destination)
|
if (joined_destination)
|
||||||
destination = joined_destination;
|
destination = joined_destination;
|
||||||
if (!destination || has_path_traversal(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");
|
log_message(LOG_LEVEL_ERROR, "Rejected destination outside authorized root");
|
||||||
free(joined_destination);
|
free(joined_destination);
|
||||||
joined_destination = NULL;
|
joined_destination = NULL;
|
||||||
|
|||||||
@@ -3,20 +3,12 @@
|
|||||||
#include "credentials.h"
|
#include "credentials.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
static void set_error(char* err, size_t err_size, const char* fmt, ...) {
|
#define set_error utils_set_error
|
||||||
if (!err || err_size == 0)
|
|
||||||
return;
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
vsnprintf(err, err_size, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void server_cli_options_default(ServerCliOptions* opts) {
|
void server_cli_options_default(ServerCliOptions* opts) {
|
||||||
if (!opts)
|
if (!opts)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/params.h>
|
#include <openssl/params.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.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_stored_key[CREDENTIAL_KEY_LEN] = {0};
|
||||||
static const uint8_t k_dummy_server_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, ...) {
|
#define set_error utils_set_error
|
||||||
if (!err || err_size == 0)
|
|
||||||
return;
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
vsnprintf(err, err_size, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_comment_char(char c) {
|
static bool is_comment_char(char c) {
|
||||||
return c == '#' || c == ';';
|
return c == '#' || c == ';';
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -17,14 +16,7 @@
|
|||||||
/* helpers */
|
/* helpers */
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
static void set_error(char* err, size_t err_size, const char* fmt, ...) {
|
#define set_error utils_set_error
|
||||||
if (!err || err_size == 0)
|
|
||||||
return;
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
vsnprintf(err, err_size, fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trim leading and trailing ASCII space/tab in place; returns the new start. */
|
/* Trim leading and trailing ASCII space/tab in place; returns the new start. */
|
||||||
static char* trim_ws(char* s) {
|
static char* trim_ws(char* s) {
|
||||||
|
|||||||
+2
-17
@@ -4,22 +4,12 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/* Write a diagnostic message into the caller's optional buffer. A NULL `err`
|
/* Write a diagnostic message into the caller's optional buffer. */
|
||||||
* (or a zero size) is a no-op, so a caller that only needs the boolean status
|
#define filter_set_error utils_set_error
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- Ordered rule lists ---- */
|
/* ---- Ordered rule lists ---- */
|
||||||
|
|
||||||
@@ -870,8 +860,3 @@ FilterAction filter_rules_apply_side(const FilterRuleList* list, const char* rel
|
|||||||
}
|
}
|
||||||
return FILTER_ACTION_NONE;
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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,
|
FilterAction filter_rules_apply_side(const FilterRuleList* list, const char* rel_path,
|
||||||
const char* leaf, bool is_dir, unsigned side);
|
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
|
#endif
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -48,6 +49,15 @@ const char* utils_get_authorized_root_path(void) {
|
|||||||
return authorized_root_path;
|
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) {
|
bool path_is_within_root(const char* root, const char* path) {
|
||||||
size_t root_len = strlen(root);
|
size_t root_len = strlen(root);
|
||||||
return strncmp(root, path, root_len) == 0 && (path[root_len] == '\0' || path[root_len] == '/');
|
return strncmp(root, path, root_len) == 0 && (path[root_len] == '\0' || path[root_len] == '/');
|
||||||
|
|||||||
@@ -225,6 +225,11 @@ void utils_set_authorized_root_fd(int fd);
|
|||||||
* threads spawn; see utils.c). */
|
* threads spawn; see utils.c). */
|
||||||
int utils_get_authorized_root_fd(void);
|
int utils_get_authorized_root_fd(void);
|
||||||
const char* utils_get_authorized_root_path(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
|
/* 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`
|
* prefix test requiring the byte after `root` to be '\0' or '/'. Both `root`
|
||||||
* and `path` must be absolute canonical paths free of "."/".." components (the
|
* and `path` must be absolute canonical paths free of "."/".." components (the
|
||||||
|
|||||||
+16
-8
@@ -179,8 +179,10 @@ static void test_filter_rules_apply_supported_modifiers() {
|
|||||||
const char* texts[] = {"- *.tmp"};
|
const char* texts[] = {"- *.tmp"};
|
||||||
FilterRuleList* list = filter_base_build(texts, 1, false, false, NULL, 0);
|
FilterRuleList* list = filter_base_build(texts, 1, false, false, NULL, 0);
|
||||||
EXPECT_NOT_NULL(list);
|
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_side(list, "b.tmp", "b.tmp", false, FILTER_SIDE_SENDER),
|
||||||
EXPECT_EQ_INT(filter_rules_apply(list, "a.txt", "a.txt", false), FILTER_ACTION_NONE);
|
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);
|
filter_rule_list_free(list);
|
||||||
}
|
}
|
||||||
/* anchored include then exclude-all */
|
/* anchored include then exclude-all */
|
||||||
@@ -188,8 +190,10 @@ static void test_filter_rules_apply_supported_modifiers() {
|
|||||||
const char* texts[] = {"+ /a.txt", "- *"};
|
const char* texts[] = {"+ /a.txt", "- *"};
|
||||||
FilterRuleList* list = filter_base_build(texts, 2, false, false, NULL, 0);
|
FilterRuleList* list = filter_base_build(texts, 2, false, false, NULL, 0);
|
||||||
EXPECT_NOT_NULL(list);
|
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_side(list, "a.txt", "a.txt", false, FILTER_SIDE_SENDER),
|
||||||
EXPECT_EQ_INT(filter_rules_apply(list, "b.txt", "b.txt", false), FILTER_ACTION_EXCLUDE);
|
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);
|
filter_rule_list_free(list);
|
||||||
}
|
}
|
||||||
/* negate */
|
/* negate */
|
||||||
@@ -197,8 +201,10 @@ static void test_filter_rules_apply_supported_modifiers() {
|
|||||||
const char* texts[] = {"-! *.o"};
|
const char* texts[] = {"-! *.o"};
|
||||||
FilterRuleList* list = filter_base_build(texts, 1, false, false, NULL, 0);
|
FilterRuleList* list = filter_base_build(texts, 1, false, false, NULL, 0);
|
||||||
EXPECT_NOT_NULL(list);
|
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_side(list, "foo.c", "foo.c", false, FILTER_SIDE_SENDER),
|
||||||
EXPECT_EQ_INT(filter_rules_apply(list, "foo.o", "foo.o", false), FILTER_ACTION_NONE);
|
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);
|
filter_rule_list_free(list);
|
||||||
}
|
}
|
||||||
/* dir-only trailing slash */
|
/* dir-only trailing slash */
|
||||||
@@ -206,8 +212,10 @@ static void test_filter_rules_apply_supported_modifiers() {
|
|||||||
const char* texts[] = {"+ dir/", "- *"};
|
const char* texts[] = {"+ dir/", "- *"};
|
||||||
FilterRuleList* list = filter_base_build(texts, 2, false, false, NULL, 0);
|
FilterRuleList* list = filter_base_build(texts, 2, false, false, NULL, 0);
|
||||||
EXPECT_NOT_NULL(list);
|
EXPECT_NOT_NULL(list);
|
||||||
EXPECT_EQ_INT(filter_rules_apply(list, "dir", "dir", true), FILTER_ACTION_INCLUDE);
|
EXPECT_EQ_INT(filter_rules_apply_side(list, "dir", "dir", true, FILTER_SIDE_SENDER),
|
||||||
EXPECT_EQ_INT(filter_rules_apply(list, "dir", "dir", false), FILTER_ACTION_EXCLUDE);
|
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);
|
filter_rule_list_free(list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user