aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/rspamc.cxx313
-rw-r--r--src/libserver/hyperscan_tools.cxx97
-rw-r--r--src/plugins/lua/mime_types.lua31
3 files changed, 232 insertions, 209 deletions
diff --git a/src/client/rspamc.cxx b/src/client/rspamc.cxx
index e934efeb1..50e3cbdee 100644
--- a/src/client/rspamc.cxx
+++ b/src/client/rspamc.cxx
@@ -362,6 +362,41 @@ struct fmt::formatter<rspamd_action_type> : fmt::formatter<string_view> {
}
};
+template<typename... T>
+static inline void rspamc_print(std::FILE *f, fmt::format_string<T...> fmt, T &&...args)
+{
+ static auto try_print_exception = true;
+ auto wanna_die = false;
+
+ try {
+ fmt::print(f, fmt, std::forward<T>(args)...);
+ } catch (const fmt::format_error &err) {
+ if (try_print_exception) {
+ if (fprintf(stderr, "Format error: %s\n", err.what()) < 0) {
+ try_print_exception = false;
+ }
+ }
+ } catch (std::system_error &err) {
+ wanna_die = true;
+ if (try_print_exception) {
+ if (fprintf(stderr, "System error: %s\n", err.what()) < 0) {
+ try_print_exception = false;
+ }
+ }
+ } catch (...) {
+ wanna_die = true;
+ if (try_print_exception) {
+ if (fprintf(stderr, "Unknown format error\n") < 0) {
+ try_print_exception = false;
+ }
+ }
+ }
+
+ if (wanna_die) {
+ exit(EXIT_FAILURE);
+ }
+}
+
using sort_lambda = std::function<int(const ucl_object_t *, const ucl_object_t *)>;
static const auto sort_map = frozen::make_unordered_map<frozen::string, sort_lambda>({
{"name", [](const ucl_object_t *o1, const ucl_object_t *o2) -> int {
@@ -507,7 +542,7 @@ rspamc_password_callback(const gchar *option_name,
processed_passwd.resize(plen, '\0');
plen = rspamd_read_passphrase(processed_passwd.data(), plen, 0, nullptr);
if (plen == 0) {
- fmt::print(stderr, "Invalid password\n");
+ rspamc_print(stderr, "Invalid password\n");
exit(EXIT_FAILURE);
}
processed_passwd.resize(plen);
@@ -536,7 +571,7 @@ read_cmd_line(gint *argc, gchar ***argv)
/* Parse options */
if (!g_option_context_parse(context, argc, argv, &error)) {
- fmt::print(stderr, "option parsing failed: {}\n", error->message);
+ rspamc_print(stderr, "option parsing failed: {}\n", error->message);
g_option_context_free(context);
exit(EXIT_FAILURE);
}
@@ -639,7 +674,7 @@ print_commands_list()
{
guint cmd_len = 0;
- fmt::print(stdout, "Rspamc commands summary:\n");
+ rspamc_print(stdout, "Rspamc commands summary:\n");
for (const auto &cmd: rspamc_commands) {
auto clen = strlen(cmd.name);
@@ -650,19 +685,19 @@ print_commands_list()
}
for (const auto &cmd: rspamc_commands) {
- fmt::print(stdout,
- " {:>{}} ({:7}{:1})\t{}\n",
- cmd.name,
- cmd_len,
- cmd.is_controller ? "control" : "normal",
- cmd.is_privileged ? "*" : "",
- cmd.description);
- }
-
- fmt::print(stdout,
- "\n* is for privileged commands that may need password (see -P option)\n");
- fmt::print(stdout,
- "control commands use port 11334 while normal use 11333 by default (see -h option)\n");
+ rspamc_print(stdout,
+ " {:>{}} ({:7}{:1})\t{}\n",
+ cmd.name,
+ cmd_len,
+ cmd.is_controller ? "control" : "normal",
+ cmd.is_privileged ? "*" : "",
+ cmd.description);
+ }
+
+ rspamc_print(stdout,
+ "\n* is for privileged commands that may need password (see -P option)\n");
+ rspamc_print(stdout,
+ "control commands use port 11334 while normal use 11333 by default (see -h option)\n");
}
static void
@@ -707,9 +742,9 @@ add_options(GQueue *opts)
freeaddrinfo(res);
}
else {
- fmt::print(stderr, "address resolution for {} failed: {}\n",
- ip,
- gai_strerror(r));
+ rspamc_print(stderr, "address resolution for {} failed: {}\n",
+ ip,
+ gai_strerror(r));
}
}
else {
@@ -847,9 +882,9 @@ rspamc_print_indented_line(FILE *out, std::string_view line) -> void
}
}
if (indent && pos) {
- fmt::print(out, "{:>{}}", " ", indent);
+ rspamc_print(out, "{:>{}}", " ", indent);
}
- fmt::print(out, "{}\n", s);
+ rspamc_print(out, "{}\n", s);
pos = line.find_first_not_of(whitespace, pos + s.size());//skip leading whitespace
}
}
@@ -904,31 +939,31 @@ rspamc_symbol_output(FILE *out, const ucl_object_t *obj)
{
auto first = true;
- fmt::print(out, "Symbol: {} ", ucl_object_key(obj));
+ rspamc_print(out, "Symbol: {} ", ucl_object_key(obj));
const auto *val = ucl_object_lookup(obj, "score");
if (val != nullptr) {
- fmt::print(out, "({:.2f})", ucl_object_todouble(val));
+ rspamc_print(out, "({:.2f})", ucl_object_todouble(val));
}
val = ucl_object_lookup(obj, "options");
if (val != nullptr && ucl_object_type(val) == UCL_ARRAY) {
ucl_object_iter_t it = nullptr;
const ucl_object_t *cur;
- fmt::print(out, "[");
+ rspamc_print(out, "[");
while ((cur = ucl_object_iterate(val, &it, true)) != nullptr) {
if (first) {
- fmt::print(out, "{}", ucl_object_tostring(cur));
+ rspamc_print(out, "{}", ucl_object_tostring(cur));
first = false;
}
else {
- fmt::print(out, ", {}", ucl_object_tostring(cur));
+ rspamc_print(out, ", {}", ucl_object_tostring(cur));
}
}
- fmt::print(out, "]");
+ rspamc_print(out, "]");
}
- fmt::print(out, "\n");
+ rspamc_print(out, "\n");
}
static void
@@ -942,16 +977,16 @@ rspamc_metric_output(FILE *out, const ucl_object_t *obj)
auto *elt = ucl_object_lookup(obj, ucl_name);
if (elt) {
if (humanreport) {
- fmt::print(out, ",{}={}", output_message, emphasis_argument(ucl_object_tostring(elt)));
+ rspamc_print(out, ",{}={}", output_message, emphasis_argument(ucl_object_tostring(elt)));
}
else {
- fmt::print(out, "{}: {}\n", output_message, emphasis_argument(ucl_object_tostring(elt)));
+ rspamc_print(out, "{}: {}\n", output_message, emphasis_argument(ucl_object_tostring(elt)));
}
}
};
if (!humanreport) {
- fmt::print(out, "[Metric: default]\n");
+ rspamc_print(out, "[Metric: default]\n");
}
const auto *elt = ucl_object_lookup(obj, "required_score");
@@ -987,12 +1022,12 @@ rspamc_metric_output(FILE *out, const ucl_object_t *obj)
if (humanreport) {
- fmt::print(out,
- "{}/{}/{}/{}",
- emphasis_argument(score, 2),
- emphasis_argument(greylist_score, 2),
- emphasis_argument(addheader_score, 2),
- emphasis_argument(required_score, 2));
+ rspamc_print(out,
+ "{}/{}/{}/{}",
+ emphasis_argument(score, 2),
+ emphasis_argument(greylist_score, 2),
+ emphasis_argument(addheader_score, 2),
+ emphasis_argument(required_score, 2));
}
elt = ucl_object_lookup(obj, "action");
@@ -1002,7 +1037,7 @@ rspamc_metric_output(FILE *out, const ucl_object_t *obj)
if (act.has_value()) {
if (!tty) {
if (humanreport) {
- fmt::print(out, ",action={}:{}", act.value(), ucl_object_tostring(elt));
+ rspamc_print(out, ",action={}:{}", act.value(), ucl_object_tostring(elt));
}
else {
print_protocol_string("action", "Action");
@@ -1032,21 +1067,21 @@ rspamc_metric_output(FILE *out, const ucl_object_t *obj)
}
if (humanreport) {
- fmt::print(out, ",action={}:{}", act.value(), colorized_action);
+ rspamc_print(out, ",action={}:{}", act.value(), colorized_action);
}
else {
- fmt::print(out, "Action: {}\n", colorized_action);
+ rspamc_print(out, "Action: {}\n", colorized_action);
}
}
is_spam = act.value() < METRIC_ACTION_GREYLIST ? true : false;
if (!humanreport) {
- fmt::print(out, "Spam: {}\n", is_spam ? "true" : "false");
+ rspamc_print(out, "Spam: {}\n", is_spam ? "true" : "false");
}
}
else {
if (humanreport) {
- fmt::print(out, ",action={}:{}", METRIC_ACTION_NOACTION, ucl_object_tostring(elt));
+ rspamc_print(out, ",action={}:{}", METRIC_ACTION_NOACTION, ucl_object_tostring(elt));
}
else {
print_protocol_string("action", "Action");
@@ -1066,21 +1101,21 @@ rspamc_metric_output(FILE *out, const ucl_object_t *obj)
is_skipped = 1;
}
- fmt::print(out, ",spam={},skipped={}\n", is_spam ? 1 : 0, is_skipped);
+ rspamc_print(out, ",spam={},skipped={}\n", is_spam ? 1 : 0, is_skipped);
}
else if (got_scores == 2) {
- fmt::print(out,
- "Score: {} / {}\n",
- emphasis_argument(score, 2),
- emphasis_argument(required_score, 2));
+ rspamc_print(out,
+ "Score: {} / {}\n",
+ emphasis_argument(score, 2),
+ emphasis_argument(required_score, 2));
}
if (humanreport) {
- fmt::print(out, "Content analysis details: ({} points, {} required)\n\n",
- emphasis_argument(score, 2),
- emphasis_argument(addheader_score, 2));
- fmt::print(out, " pts rule name description\n");
- fmt::print(out, "---- ---------------------- --------------------------------------------------\n");
+ rspamc_print(out, "Content analysis details: ({} points, {} required)\n\n",
+ emphasis_argument(score, 2),
+ emphasis_argument(addheader_score, 2));
+ rspamc_print(out, " pts rule name description\n");
+ rspamc_print(out, "---- ---------------------- --------------------------------------------------\n");
}
elt = ucl_object_lookup(obj, "symbols");
@@ -1101,7 +1136,7 @@ rspamc_metric_output(FILE *out, const ucl_object_t *obj)
}
}
if (humanreport) {
- fmt::print(out, "\n");
+ rspamc_print(out, "\n");
}
}
@@ -1122,8 +1157,8 @@ rspamc_profile_output(FILE *out, const ucl_object_t *obj)
});
for (const auto *cur_elt: ar) {
- fmt::print(out, "\t{}: {:3} usec\n",
- ucl_object_key(cur_elt), ucl_object_todouble(cur_elt));
+ rspamc_print(out, "\t{}: {:3} usec\n",
+ ucl_object_key(cur_elt), ucl_object_todouble(cur_elt));
}
}
@@ -1135,7 +1170,7 @@ rspamc_symbols_output(FILE *out, ucl_object_t *obj)
auto print_protocol_string = [&](const char *ucl_name, const char *output_message) {
auto *elt = ucl_object_lookup(obj, ucl_name);
if (elt) {
- fmt::print(out, "{}: {}\n", output_message, ucl_object_tostring(elt));
+ rspamc_print(out, "{}: {}\n", output_message, ucl_object_tostring(elt));
}
};
@@ -1162,7 +1197,7 @@ rspamc_symbols_output(FILE *out, ucl_object_t *obj)
}
}
else {
- fmt::print(out, "Urls: {}\n", emitted);
+ rspamc_print(out, "Urls: {}\n", emitted);
}
free(emitted);
}
@@ -1184,7 +1219,7 @@ rspamc_symbols_output(FILE *out, ucl_object_t *obj)
}
}
else {
- fmt::print(out, "Emails: {}\n", emitted);
+ rspamc_print(out, "Emails: {}\n", emitted);
}
free(emitted);
}
@@ -1201,14 +1236,14 @@ rspamc_symbols_output(FILE *out, ucl_object_t *obj)
while ((cmesg = ucl_object_iterate(elt, &mit, true)) != nullptr) {
if (ucl_object_type(cmesg) == UCL_STRING) {
- fmt::print(out, "Message - {}: {}\n",
- ucl_object_key(cmesg), ucl_object_tostring(cmesg));
+ rspamc_print(out, "Message - {}: {}\n",
+ ucl_object_key(cmesg), ucl_object_tostring(cmesg));
}
else {
char *rendered_message;
rendered_message = (char *) ucl_object_emit(cmesg, UCL_EMIT_JSON_COMPACT);
- fmt::print(out, "Message - {}: {:.60}\n",
- ucl_object_key(cmesg), rendered_message);
+ rspamc_print(out, "Message - {}: {:.60}\n",
+ ucl_object_key(cmesg), rendered_message);
free(rendered_message);
}
}
@@ -1216,21 +1251,21 @@ rspamc_symbols_output(FILE *out, ucl_object_t *obj)
elt = ucl_object_lookup(obj, "dkim-signature");
if (elt && elt->type == UCL_STRING) {
- fmt::print(out, "DKIM-Signature: {}\n", ucl_object_tostring(elt));
+ rspamc_print(out, "DKIM-Signature: {}\n", ucl_object_tostring(elt));
}
else if (elt && elt->type == UCL_ARRAY) {
ucl_object_iter_t it = nullptr;
const ucl_object_t *cur;
while ((cur = ucl_object_iterate(elt, &it, true)) != nullptr) {
- fmt::print(out, "DKIM-Signature: {}\n", ucl_object_tostring(cur));
+ rspamc_print(out, "DKIM-Signature: {}\n", ucl_object_tostring(cur));
}
}
elt = ucl_object_lookup(obj, "profile");
if (elt) {
- fmt::print(out, "Profile data:\n");
+ rspamc_print(out, "Profile data:\n");
rspamc_profile_output(out, elt);
}
}
@@ -1242,34 +1277,34 @@ rspamc_uptime_output(FILE *out, ucl_object_t *obj)
const auto *elt = ucl_object_lookup(obj, "version");
if (elt != nullptr) {
- fmt::print(out, "Rspamd version: {}\n", ucl_object_tostring(elt));
+ rspamc_print(out, "Rspamd version: {}\n", ucl_object_tostring(elt));
}
elt = ucl_object_lookup(obj, "uptime");
if (elt != nullptr) {
- fmt::print("Uptime: ");
+ rspamc_print(out, "Uptime: ");
seconds = ucl_object_toint(elt);
if (seconds >= 2 * 3600) {
days = seconds / 86400;
hours = seconds / 3600 - days * 24;
minutes = seconds / 60 - hours * 60 - days * 1440;
- fmt::print("{} day{} {} hour{} {} minute{}\n", days,
- days > 1 ? "s" : "", hours, hours > 1 ? "s" : "",
- minutes, minutes > 1 ? "s" : "");
+ rspamc_print(out, "{} day{} {} hour{} {} minute{}\n", days,
+ days > 1 ? "s" : "", hours, hours > 1 ? "s" : "",
+ minutes, minutes > 1 ? "s" : "");
}
/* If uptime is less than 1 minute print only seconds */
else if (seconds / 60 == 0) {
- fmt::print("{} second{}\n", seconds,
- seconds > 1 ? "s" : "");
+ rspamc_print(out, "{} second{}\n", seconds,
+ seconds > 1 ? "s" : "");
}
/* Else print the minutes and seconds. */
else {
hours = seconds / 3600;
minutes = seconds / 60 - hours * 60;
seconds -= hours * 3600 + minutes * 60;
- fmt::print("{} hour {} minute{} {} second{}\n", hours,
- minutes, minutes > 1 ? "s" : "",
- seconds, seconds > 1 ? "s" : "");
+ rspamc_print(out, "{} hour {} minute{} {} second{}\n", hours,
+ minutes, minutes > 1 ? "s" : "",
+ seconds, seconds > 1 ? "s" : "");
}
}
}
@@ -1278,7 +1313,7 @@ static void
rspamc_counters_output(FILE *out, ucl_object_t *obj)
{
if (obj->type != UCL_ARRAY) {
- fmt::print(out, "Bad output\n");
+ rspamc_print(out, "Bad output\n");
return;
}
@@ -1309,24 +1344,24 @@ rspamc_counters_output(FILE *out, ucl_object_t *obj)
memset(dash_buf, '-', dashes + max_len);
dash_buf[dashes + max_len] = '\0';
- fmt::print(out, "Symbols cache\n");
-
- fmt::print(out, " {} \n", emphasis_argument(dash_buf));
- fmt::print(out,
- "| {:<4} | {:<{}} | {:^7} | {:^13} | {:^7} |\n",
- "Pri",
- "Symbol",
- max_len,
- "Weight",
- "Frequency",
- "Hits");
- fmt::print(out, " {} \n", emphasis_argument(dash_buf));
- fmt::print(out, "| {:<4} | {:<{}} | {:^7} | {:^13} | {:^7} |\n", "",
- "", max_len,
- "", "hits/min", "");
+ rspamc_print(out, "Symbols cache\n");
+
+ rspamc_print(out, " {} \n", emphasis_argument(dash_buf));
+ rspamc_print(out,
+ "| {:<4} | {:<{}} | {:^7} | {:^13} | {:^7} |\n",
+ "Pri",
+ "Symbol",
+ max_len,
+ "Weight",
+ "Frequency",
+ "Hits");
+ rspamc_print(out, " {} \n", emphasis_argument(dash_buf));
+ rspamc_print(out, "| {:<4} | {:<{}} | {:^7} | {:^13} | {:^7} |\n", "",
+ "", max_len,
+ "", "hits/min", "");
for (const auto [i, cur]: rspamd::enumerate(counters_vec)) {
- fmt::print(out, " {} \n", dash_buf);
+ rspamc_print(out, " {} \n", dash_buf);
const auto *sym = ucl_object_lookup(cur, "symbol");
const auto *weight = ucl_object_lookup(cur, "weight");
const auto *freq = ucl_object_lookup(cur, "frequency");
@@ -1345,16 +1380,16 @@ rspamc_counters_output(FILE *out, ucl_object_t *obj)
sym_name = ucl_object_tostring(sym);
}
- fmt::print(out, "| {:<4} | {:<{}} | {:^7.1f} | {:^6.3f}({:^5.3f}) | {:^7} |\n", i,
- sym_name,
- max_len,
- ucl_object_todouble(weight),
- ucl_object_todouble(freq) * 60.0,
- ucl_object_todouble(freq_dev) * 60.0,
- (std::uintmax_t) ucl_object_toint(nhits));
+ rspamc_print(out, "| {:<4} | {:<{}} | {:^7.1f} | {:^6.3f}({:^5.3f}) | {:^7} |\n", i,
+ sym_name,
+ max_len,
+ ucl_object_todouble(weight),
+ ucl_object_todouble(freq) * 60.0,
+ ucl_object_todouble(freq_dev) * 60.0,
+ (std::uintmax_t) ucl_object_toint(nhits));
}
}
- fmt::print(out, " {} \n", dash_buf);
+ rspamc_print(out, " {} \n", dash_buf);
}
static void
@@ -1531,7 +1566,7 @@ rspamc_stat_output(FILE *out, ucl_object_t *obj)
fmt::format_to(std::back_inserter(out_str), "Total learns: {}\n",
ucl_object_toint(ucl_object_lookup(obj, "total_learns")));
- fmt::print(out, "{}", out_str.c_str());
+ rspamc_print(out, "{}", out_str.c_str());
}
static void
@@ -1540,11 +1575,11 @@ rspamc_output_headers(FILE *out, struct rspamd_http_message *msg)
struct rspamd_http_header *h;
kh_foreach_value(msg->headers, h, {
- fmt::print(out, "{}: {}\n", std::string_view{h->name.begin, h->name.len},
- std::string_view{h->value.begin, h->value.len});
+ rspamc_print(out, "{}: {}\n", std::string_view{h->name.begin, h->name.len},
+ std::string_view{h->value.begin, h->value.len});
});
- fmt::print(out, "\n");
+ rspamc_print(out, "\n");
}
static void
@@ -1559,7 +1594,7 @@ rspamc_mime_output(FILE *out, ucl_object_t *result, GString *input,
auto headers_pos = rspamd_string_find_eoh(input, nullptr);
if (headers_pos == -1) {
- fmt::print(stderr, "cannot find end of headers position");
+ rspamc_print(stderr, "cannot find end of headers position");
return;
}
@@ -1704,11 +1739,11 @@ rspamc_mime_output(FILE *out, ucl_object_t *result, GString *input,
/* Write message */
/* Original headers */
- fmt::print(out, "{}", std::string_view{input->str, (std::size_t) headers_pos});
+ rspamc_print(out, "{}", std::string_view{input->str, (std::size_t) headers_pos});
/* Added headers */
- fmt::print(out, "{}", added_headers);
+ rspamc_print(out, "{}", added_headers);
/* Message body */
- fmt::print(out, "{}", input->str + headers_pos);
+ rspamc_print(out, "{}", input->str + headers_pos);
}
static void
@@ -1721,7 +1756,7 @@ rspamc_client_execute_cmd(const struct rspamc_command &cmd, ucl_object_t *result
GPid cld;
if (!g_shell_parse_argv(execute, &eargc, &eargv, &err)) {
- fmt::print(stderr, "Cannot execute {}: {}", execute, err->message);
+ rspamc_print(stderr, "Cannot execute {}: {}", execute, err->message);
g_error_free(err);
return;
@@ -1731,7 +1766,7 @@ rspamc_client_execute_cmd(const struct rspamc_command &cmd, ucl_object_t *result
static_cast<GSpawnFlags>(G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD), nullptr, nullptr, &cld,
&infd, &outfd, &errfd, &exec_err)) {
- fmt::print(stderr, "Cannot execute {}: {}", execute, exec_err->message);
+ rspamc_print(stderr, "Cannot execute {}: {}", execute, exec_err->message);
g_error_free(exec_err);
exit(EXIT_FAILURE);
@@ -1755,7 +1790,7 @@ rspamc_client_execute_cmd(const struct rspamc_command &cmd, ucl_object_t *result
ucl_out = (char *) ucl_object_emit(result,
compact ? UCL_EMIT_JSON_COMPACT : UCL_EMIT_CONFIG);
}
- fmt::print(out, "{}", ucl_out);
+ rspamc_print(out, "{}", ucl_out);
free(ucl_out);
}
else {
@@ -1765,7 +1800,7 @@ rspamc_client_execute_cmd(const struct rspamc_command &cmd, ucl_object_t *result
ucl_object_unref(result);
}
else {
- fmt::print(out, "{}\n", err->message);
+ rspamc_print(out, "{}\n", err->message);
}
fflush(out);
@@ -1817,14 +1852,14 @@ rspamc_client_cb(struct rspamd_client_connection *conn,
else {
if (cmd.need_input && !json) {
if (!compact && !humanreport) {
- fmt::print(out, "Results for file: {} ({:.3} seconds)\n",
- emphasis_argument(cbdata->filename), diff);
+ rspamc_print(out, "Results for file: {} ({:.3} seconds)\n",
+ emphasis_argument(cbdata->filename), diff);
}
}
else {
if (!compact && !json && !humanreport) {
- fmt::print(out, "Results for command: {} ({:.3} seconds)\n",
- emphasis_argument(cmd.name), diff);
+ rspamc_print(out, "Results for command: {} ({:.3} seconds)\n",
+ emphasis_argument(cmd.name), diff);
}
}
@@ -1856,7 +1891,7 @@ rspamc_client_cb(struct rspamd_client_connection *conn,
compact ? UCL_EMIT_JSON_COMPACT : UCL_EMIT_CONFIG);
}
- fmt::print(out, "{}", ucl_out);
+ rspamc_print(out, "{}", ucl_out);
free(ucl_out);
}
else {
@@ -1864,14 +1899,14 @@ rspamc_client_cb(struct rspamd_client_connection *conn,
}
if (body) {
- fmt::print(out, "\nNew body:\n{}\n",
- std::string_view{body, bodylen});
+ rspamc_print(out, "\nNew body:\n{}\n",
+ std::string_view{body, bodylen});
}
ucl_object_unref(result);
}
else if (err != nullptr) {
- fmt::print(out, "{}\n", err->message);
+ rspamc_print(out, "{}\n", err->message);
if (json && msg != nullptr) {
gsize rawlen;
@@ -1880,11 +1915,11 @@ rspamc_client_cb(struct rspamd_client_connection *conn,
if (raw_body) {
/* We can also output the resulting json */
- fmt::print(out, "{}\n", std::string_view{raw_body, (std::size_t)(rawlen - bodylen)});
+ rspamc_print(out, "{}\n", std::string_view{raw_body, (std::size_t)(rawlen - bodylen)});
}
}
}
- fmt::print(out, "\n");
+ rspamc_print(out, "\n");
}
fflush(out);
@@ -1979,8 +2014,8 @@ rspamc_process_input(struct ev_loop *ev_base, const struct rspamc_command &cmd,
}
}
else {
- fmt::print(stderr, "cannot connect to {}: {}\n", connect_str,
- strerror(errno));
+ rspamc_print(stderr, "cannot connect to {}: {}\n", connect_str,
+ strerror(errno));
exit(EXIT_FAILURE);
}
}
@@ -2069,8 +2104,8 @@ rspamc_process_dir(struct ev_loop *ev_base, const struct rspamc_command &cmd,
if (pentry->d_type == DT_UNKNOWN) {
/* Fallback to lstat */
if (lstat(fpath.c_str(), &st) == -1) {
- fmt::print(stderr, "cannot stat file {}: {}\n",
- fpath, strerror(errno));
+ rspamc_print(stderr, "cannot stat file {}: {}\n",
+ fpath, strerror(errno));
continue;
}
@@ -2087,8 +2122,8 @@ rspamc_process_dir(struct ev_loop *ev_base, const struct rspamc_command &cmd,
}
#else
if (lstat(fpath.c_str(), &st) == -1) {
- fmt::print(stderr, "cannot stat file {}: {}\n",
- fpath, strerror(errno));
+ rspamc_print(stderr, "cannot stat file {}: {}\n",
+ fpath, strerror(errno));
continue;
}
@@ -2102,8 +2137,8 @@ rspamc_process_dir(struct ev_loop *ev_base, const struct rspamc_command &cmd,
else if (is_reg) {
auto *in = fopen(fpath.c_str(), "r");
if (in == nullptr) {
- fmt::print(stderr, "cannot open file {}: {}\n",
- fpath, strerror(errno));
+ rspamc_print(stderr, "cannot open file {}: {}\n",
+ fpath, strerror(errno));
continue;
}
@@ -2120,7 +2155,7 @@ rspamc_process_dir(struct ev_loop *ev_base, const struct rspamc_command &cmd,
}
}
else {
- fmt::print(stderr, "cannot open directory {}: {}\n", name, strerror(errno));
+ rspamc_print(stderr, "cannot open directory {}: {}\n", name, strerror(errno));
exit(EXIT_FAILURE);
}
@@ -2167,8 +2202,8 @@ int main(int argc, char **argv, char **env)
exclude_compiled[i] = g_pattern_spec_new(exclude_patterns[i]);
if (exclude_compiled[i] == nullptr) {
- fmt::print(stderr, "Invalid glob pattern: {}\n",
- exclude_patterns[i]);
+ rspamc_print(stderr, "Invalid glob pattern: {}\n",
+ exclude_patterns[i]);
exit(EXIT_FAILURE);
}
}
@@ -2223,7 +2258,7 @@ int main(int argc, char **argv, char **env)
/* In case of command read arguments starting from 2 */
if (cmd.cmd == RSPAMC_COMMAND_ADD_SYMBOL || cmd.cmd == RSPAMC_COMMAND_ADD_ACTION) {
if (argc < 4 || argc > 5) {
- fmt::print(stderr, "invalid arguments\n");
+ rspamc_print(stderr, "invalid arguments\n");
exit(EXIT_FAILURE);
}
if (argc == 5) {
@@ -2248,7 +2283,7 @@ int main(int argc, char **argv, char **env)
}
if (!maybe_cmd.has_value()) {
- fmt::print(stderr, "invalid command\n");
+ rspamc_print(stderr, "invalid command\n");
exit(EXIT_FAILURE);
}
@@ -2275,7 +2310,7 @@ int main(int argc, char **argv, char **env)
struct stat st;
if (stat(argv[i], &st) == -1) {
- fmt::print(stderr, "cannot stat file {}\n", argv[i]);
+ rspamc_print(stderr, "cannot stat file {}\n", argv[i]);
exit(EXIT_FAILURE);
}
if (S_ISDIR(st.st_mode)) {
@@ -2286,7 +2321,7 @@ int main(int argc, char **argv, char **env)
else {
in = fopen(argv[i], "r");
if (in == nullptr) {
- fmt::print(stderr, "cannot open file {}\n", argv[i]);
+ rspamc_print(stderr, "cannot open file {}\n", argv[i]);
exit(EXIT_FAILURE);
}
rspamc_process_input(event_loop, cmd, in, argv[i], kwattrs);
@@ -2316,8 +2351,8 @@ int main(int argc, char **argv, char **env)
for (auto cld: children) {
auto res = 0;
if (waitpid(cld, &res, 0) == -1) {
- fmt::print(stderr, "Cannot wait for {}: {}", cld,
- strerror(errno));
+ rspamc_print(stderr, "Cannot wait for {}: {}", cld,
+ strerror(errno));
ret = errno;
}
diff --git a/src/libserver/hyperscan_tools.cxx b/src/libserver/hyperscan_tools.cxx
index ec051837e..dc0586107 100644
--- a/src/libserver/hyperscan_tools.cxx
+++ b/src/libserver/hyperscan_tools.cxx
@@ -18,6 +18,7 @@
#ifdef WITH_HYPERSCAN
#include <string>
+#include <filesystem>
#include "contrib/ankerl/unordered_dense.h"
#include "contrib/ankerl/svector.h"
#include "fmt/core.h"
@@ -103,41 +104,6 @@ private:
cleanup_maybe();
}
- /* Have to duplicate raii_file methods to use raw filenames */
- static auto get_dir(std::string_view fname) -> std::string_view
- {
- auto sep_pos = fname.rfind(G_DIR_SEPARATOR);
-
- if (sep_pos == std::string::npos) {
- return std::string_view{fname};
- }
-
- while (sep_pos >= 1 && fname[sep_pos - 1] == G_DIR_SEPARATOR) {
- sep_pos--;
- }
-
- return std::string_view{fname.data(), sep_pos};
- }
-
- static auto get_extension(std::string_view fname) -> std::string_view
- {
- auto sep_pos = fname.rfind(G_DIR_SEPARATOR);
-
- if (sep_pos == std::string::npos) {
- sep_pos = 0;
- }
-
- auto filename = std::string_view{fname.data() + sep_pos};
- auto dot_pos = filename.find('.');
-
- if (dot_pos == std::string::npos) {
- return std::string_view{};
- }
- else {
- return std::string_view{filename.data() + dot_pos + 1, filename.size() - dot_pos - 1};
- }
- }
-
public:
hs_known_files_cache(const hs_known_files_cache &) = delete;
hs_known_files_cache(hs_known_files_cache &&) = delete;
@@ -176,69 +142,72 @@ public:
void add_cached_file(const char *fname)
{
- auto mut_fname = std::string{fname};
- std::size_t sz;
+ auto fpath = std::filesystem::path{fname};
+ std::error_code ec;
- rspamd_normalize_path_inplace(mut_fname.data(), mut_fname.size(), &sz);
- mut_fname.resize(sz);
+ fpath = std::filesystem::canonical(fpath, ec);
- if (mut_fname.empty()) {
+ if (!ec) {
+ msg_err_hyperscan("invalid path: \"%s\", error message: %s", fname, ec.message().c_str());
+ return;
+ }
+
+ if (fpath.empty()) {
msg_err_hyperscan("attempt to add an empty hyperscan file!");
return;
}
- if (access(mut_fname.c_str(), R_OK) == -1) {
- msg_err_hyperscan("attempt to add non existing hyperscan file: %s, %s", mut_fname.c_str(),
+ if (!std::filesystem::exists(fpath)) {
+ msg_err_hyperscan("attempt to add non existing hyperscan file: %s, %s", fpath.c_str(),
strerror(errno));
return;
}
- auto dir = hs_known_files_cache::get_dir(mut_fname);
- auto ext = hs_known_files_cache::get_extension(mut_fname);
+ auto dir = fpath.parent_path();
+ auto ext = fpath.extension();
if (std::find_if(cache_dirs.begin(), cache_dirs.end(),
[&](const auto &item) { return item == dir; }) == std::end(cache_dirs)) {
- cache_dirs.emplace_back(std::string{dir});
+ cache_dirs.emplace_back(dir.string());
}
if (std::find_if(cache_extensions.begin(), cache_extensions.end(),
[&](const auto &item) { return item == ext; }) == std::end(cache_extensions)) {
- cache_extensions.emplace_back(std::string{ext});
+ cache_extensions.emplace_back(ext.string());
}
- auto is_known = known_cached_files.insert(mut_fname);
+ auto is_known = known_cached_files.insert(fpath.string());
msg_debug_hyperscan("added %s hyperscan file: %s",
is_known.second ? "new" : "already known",
- mut_fname.c_str());
+ fpath.c_str());
}
void delete_cached_file(const char *fname)
{
- auto mut_fname = std::string{fname};
- std::size_t sz;
+ auto fpath = std::filesystem::path{fname};
+ std::error_code ec;
+
+ fpath = std::filesystem::canonical(fpath, ec);
- rspamd_normalize_path_inplace(mut_fname.data(), mut_fname.size(), &sz);
- mut_fname.resize(sz);
+ if (!ec) {
+ msg_err_hyperscan("invalid path to remove: \"%s\", error message: %s",
+ fname, ec.message().c_str());
+ return;
+ }
- if (mut_fname.empty()) {
+ if (fpath.empty()) {
msg_err_hyperscan("attempt to remove an empty hyperscan file!");
return;
}
- if (access(mut_fname.c_str(), R_OK) != -1) {
- if (unlink(mut_fname.c_str()) == -1) {
- msg_err_hyperscan("cannot remove hyperscan file %s: %s",
- mut_fname.c_str(), strerror(errno));
- }
- else {
- msg_debug_hyperscan("removed hyperscan file %s", mut_fname.c_str());
- }
+ if (unlink(fpath.c_str()) == -1) {
+ msg_err_hyperscan("cannot remove hyperscan file %s: %s",
+ fpath.c_str(), strerror(errno));
}
else {
- msg_err_hyperscan("attempt to remove non-existent hyperscan file %s: %s",
- mut_fname.c_str(), strerror(errno));
+ msg_debug_hyperscan("removed hyperscan file %s", fpath.c_str());
}
- known_cached_files.erase(mut_fname);
+ known_cached_files.erase(fpath.string());
}
auto cleanup_maybe() -> void
diff --git a/src/plugins/lua/mime_types.lua b/src/plugins/lua/mime_types.lua
index bfe0d6327..ebd8a8028 100644
--- a/src/plugins/lua/mime_types.lua
+++ b/src/plugins/lua/mime_types.lua
@@ -52,16 +52,10 @@ local settings = {
},
bad_extensions = {
- bat = 2,
- chm = 4,
- com = 2,
cue = 2,
exe = 1,
- hta = 2,
iso = 4,
jar = 2,
- lnk = 4,
- scr = 4,
-- In contrast to HTML MIME parts, dedicated HTML attachments are considered harmful
htm = 1,
html = 1,
@@ -70,11 +64,21 @@ local settings = {
-- Have you ever seen that in legit email?
ace = 4,
arj = 2,
+ aspx = 1,
asx = 2,
cab = 3,
+ dll = 4,
+ dqy = 2,
+ iqy = 2,
+ mht = 2,
+ mhtml = 2,
+ oqy = 2,
+ rqy = 2,
sfx = 2,
+ slk = 2,
vst = 2,
vss = 2,
+ wim = 2,
-- Additional bad extensions from Gmail
ade = 4,
adp = 4,
@@ -105,7 +109,10 @@ local settings = {
app = 4,
asp = 4,
bas = 4,
+ bat = 4,
+ chm = 4,
cnt = 4,
+ com = 4,
csh = 4,
diagcab = 4,
fxp = 4,
@@ -113,9 +120,12 @@ local settings = {
grp = 4,
hlp = 4,
hpj = 4,
+ hta = 4,
+ htc = 4,
inf = 4,
its = 4,
jnlp = 4,
+ lnk = 4,
ksh = 4,
mad = 4,
maf = 4,
@@ -158,17 +168,26 @@ local settings = {
psd1 = 4,
psdm1 = 4,
pst = 4,
+ pyc = 4,
+ pyo = 4,
+ pyw = 4,
+ pyz = 4,
+ pyzw = 4,
reg = 4,
scf = 4,
+ scr = 4,
shs = 4,
theme = 4,
url = 4,
vbp = 4,
+ vhd = 4,
+ vhdx = 4,
vsmacros = 4,
vsw = 4,
webpnp = 4,
website = 4,
ws = 4,
+ wsf = 4,
xbap = 4,
xll = 4,
xnk = 4,