diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/rspamc.cxx | 313 | ||||
-rw-r--r-- | src/libserver/hyperscan_tools.cxx | 97 | ||||
-rw-r--r-- | src/plugins/lua/mime_types.lua | 31 |
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, |