From ebad7632303fe5ee99e7d6ee93c9a03eabf18eb7 Mon Sep 17 00:00:00 2001 From: De Rais Date: Sun, 7 Jun 2020 14:58:00 -0400 Subject: [PATCH] server: tie regex filters to db_insert_ban --- config.def.h | 8 ++++++-- rb79-server.c | 44 +++++++++++++++++++++++++++++++++++--------- rb79.h | 9 ++++++++- sanitize-comment.c | 53 ++++++++++++++++++++++++++++++++--------------------- 4 files changed, 81 insertions(+), 33 deletions(-) diff --git a/config.def.h b/config.def.h index 0385379..ed136c3 100644 --- a/config.def.h +++ b/config.def.h @@ -423,9 +423,13 @@ static const struct wordfilter_input wordfilter_inputs[] = { /* * What are some phrases that can't be posted? As with wordfilters, * pattern will be compiled with pcre2, only with the UTF compatible - * option. + * option. ban_duration is (if non-zero) the amount of time they'll be + * banned for, with reason ban_reason (secret if empty) */ static const struct forbidden_input forbidden_inputs[] = { /* */ - { .pattern = "Actually [Ss][Ee][Ee][Dd] Destiny was good" }, + { .pattern = "Actually [Ss][Ee][Ee][Dd] Destiny was good", + .ban_duration = 43200, .ban_reason = "I disagree" }, + { .pattern = "dick pills", .ban_duration = 31536000, + .ban_reason = 0 }, }; diff --git a/rb79-server.c b/rb79-server.c index 4532db4..599eaa8 100644 --- a/rb79-server.c +++ b/rb79-server.c @@ -253,7 +253,6 @@ handle_op_or_reply(struct configuration *conf, FCGX_Request *r, struct { char *buf = 0; char *abs_file_path = 0; - size_t len = 0; int our_fault = 0; uintmax_t real_thread = 0; int cooldown = 0; @@ -325,17 +324,43 @@ handle_op_or_reply(struct configuration *conf, FCGX_Request *r, struct } /* HTML-escape, wordfilter, linkify */ - if (st_sanitize_text(pc, &our_fault) < 0) { + uint_fast8_t is_forbidden = 0; + int ban_duration = 0; + const char *ban_reason = 0; + + if (st_sanitize_text(pc, &our_fault, &is_forbidden, &ban_duration, + &ban_reason) < 0) { if (our_fault) { LOG("Error in st_sanitize_text (500)"); report_internal_error(r); goto done; } - LOG("Bad text (400)"); - LOG("Comment was \"%s\"", UBSAFES(pc->raw.comment)); - report_bad_request(r, "Disallowed text"); - goto done; + if (is_forbidden) { + LOG("Bad text (400)"); + LOG("Comment was \"%s\"", UBSAFES(pc->raw.comment)); + + if (ban_duration) { + time_t start = time(0); + time_t end = start + ban_duration; + int is_secret = !(ban_reason); + + if (db_insert_ban(1, 0, ip, ip, ban_reason, + is_secret, start, end) < 0) { + LOG("Error in db_insert_ban (500)"); + report_internal_error(r); + goto done; + } + } + + report_bad_request(r, "Disallowed text"); + goto done; + } else { + LOG("Unknown error (400)"); + LOG("Comment was \"%s\"", UBSAFES(pc->raw.comment)); + report_bad_request(r, "Disallowed text"); + goto done; + } } cooldown = pc->prepared.comment_len ? @@ -671,15 +696,15 @@ handle(struct configuration *conf, FCGX_Request *r) if (is_banned) { if (is_secret) { - LOG("Ban[s] (until=\%s\", reason=\"%s\") (200)", - ban_until, ban_reason); + LOG("Ban[s] (until=\"%s\", reason=\"%s\") (200)", + ban_until, UBSAFES(ban_reason)); report_post_successful_with_redir(r, post_cmd.raw.board); goto done; } else { /* This should give HTTP 403 */ LOG("Ban (until=\"%s\", reason=\"%s\") (403)", - ban_until, ban_reason); + ban_until, UBSAFES(ban_reason)); report_ban(r, ban_until, ban_reason); goto done; } @@ -787,6 +812,7 @@ done: free(ban_reason); free(ban_until); free(cooldown_length); + free(ip); } /* Do the thing */ diff --git a/rb79.h b/rb79.h index 3183cf0..9c82e8f 100644 --- a/rb79.h +++ b/rb79.h @@ -106,6 +106,9 @@ struct post_cmd { * Parsing, if needed, is done by rb79.c */ struct { + /* 0-terminated and normalized */ + char *ip; + /* action= */ char *action; size_t action_len; @@ -223,6 +226,8 @@ struct wordfilter_input { struct forbidden_input { /* */ const char *pattern; + int ban_duration; + const char *ban_reason; }; /* See config.def.h for detailed descriptions. */ @@ -345,7 +350,9 @@ int preconditions_check(const struct configuration *conf); /* sanitize-comment.c */ int setup_sanitize_comment(const struct configuration *conf); -int st_sanitize_text(struct post_cmd *pc, int *our_fault); +int st_sanitize_text(struct post_cmd *pc, int *our_fault, + uint_fast8_t *is_forbidden, int *ban_duration, const + char **ban_reason); int clean_sanitize_comment(void); diff --git a/sanitize-comment.c b/sanitize-comment.c index a1064d6..bed2ad6 100644 --- a/sanitize-comment.c +++ b/sanitize-comment.c @@ -58,6 +58,8 @@ struct wordfilter { struct forbidden { /* */ pcre2_code *code; + int ban_duration; + const char *ban_reason; }; /* These are constructed in setup_sanitize_comment() */ @@ -538,16 +540,19 @@ done: * * - scannable is memory of length at least scannable_len. * - * - is_forbidden is not 0. + * - out_is_forbidden, out_ban_duration, out_ban_reason are not 0. * * Postconditions (success): * * - if any regex specified by the forbidden array matches scannable, - * then *is_forbidden has been set to 1. + * then *out_is_forbidden has been set to 1, with relevant + * *out_ban_duration, *out_ban_reason. */ static int check_forbidden_filters(const char *scannable, const size_t scannable_len, - uint_fast8_t *is_forbidden) + uint_fast8_t *out_is_forbidden, int *out_ban_duration, + const + char **out_ban_reason) { int ret = -1; @@ -567,7 +572,9 @@ check_forbidden_filters(const char *scannable, const size_t scannable_len, 0, 0, match_data, 0); if (num_matches > 0) { - *is_forbidden = 1; + *out_is_forbidden = 1; + *out_ban_duration = forbiddens[j].ban_duration; + *out_ban_reason = forbiddens[j].ban_reason; j = forbiddens_num; } @@ -1106,11 +1113,12 @@ done: * is valid ASCII text, with Unicode codepoints. */ int -st_sanitize_text(struct post_cmd *pc, int *our_fault) +st_sanitize_text(struct post_cmd *pc, int *our_fault, + uint_fast8_t *is_forbidden, int *ban_duration, const + char **ban_reason) { int ret = -1; size_t out_idx = 0; - uint_fast8_t is_forbidden = 0; char *html_escaped_comment = 0; size_t html_escaped_comment_len = 0; @@ -1232,17 +1240,15 @@ st_sanitize_text(struct post_cmd *pc, int *our_fault) goto done; } - if (to_scannable(pc->raw.name, pc->raw.name_len, - &pc->scannable_name, &pc->scannable_name_len, - &pc->name_position_map, + if (to_scannable(pc->raw.name, pc->raw.name_len, &pc->scannable_name, + &pc->scannable_name_len, &pc->name_position_map, &pc->name_position_map_len)) { *our_fault = 1; goto done; } - if (to_scannable(pc->raw.email, pc->raw.email_len, - &pc->scannable_email, &pc->scannable_email_len, - &pc->email_position_map, + if (to_scannable(pc->raw.email, pc->raw.email_len, &pc->scannable_email, + &pc->scannable_email_len, &pc->email_position_map, &pc->email_position_map_len)) { *our_fault = 1; goto done; @@ -1260,34 +1266,36 @@ st_sanitize_text(struct post_cmd *pc, int *our_fault) * Are they a spambot? */ if (check_forbidden_filters(pc->scannable_comment, - pc->scannable_comment_len, &is_forbidden) < + pc->scannable_comment_len, is_forbidden, + ban_duration, ban_reason) < 0) { *our_fault = 1; goto done; } - if (check_forbidden_filters(pc->scannable_name, - pc->scannable_name_len, &is_forbidden) < + if (check_forbidden_filters(pc->scannable_name, pc->scannable_name_len, + is_forbidden, ban_duration, ban_reason) < 0) { *our_fault = 1; goto done; } if (check_forbidden_filters(pc->scannable_email, - pc->scannable_email_len, &is_forbidden) < - 0) { + pc->scannable_email_len, is_forbidden, + ban_duration, ban_reason) < 0) { *our_fault = 1; goto done; } if (check_forbidden_filters(pc->scannable_subject, - pc->scannable_subject_len, &is_forbidden) < + pc->scannable_subject_len, is_forbidden, + ban_duration, ban_reason) < 0) { *our_fault = 1; goto done; } - if (is_forbidden) { + if (*is_forbidden) { *our_fault = 0; goto done; } @@ -1298,8 +1306,7 @@ st_sanitize_text(struct post_cmd *pc, int *our_fault) */ if (wordfilter_to_html(pc->raw.comment, pc->raw.comment_len, pc->scannable_comment, pc->scannable_comment_len, - pc->comment_position_map, - &html_escaped_comment, + pc->comment_position_map, &html_escaped_comment, &html_escaped_comment_len) < 0) { *our_fault = 1; goto done; @@ -1429,6 +1436,10 @@ setup_sanitize_comment(const struct configuration *conf) forbiddens_num = conf->forbidden_inputs_num; for (size_t j = 0; j < forbiddens_num; ++j) { + forbiddens[j].ban_duration = + conf->forbidden_inputs[j].ban_duration; + forbiddens[j].ban_reason = conf->forbidden_inputs[j].ban_reason; + if ((forbiddens[j].code = pcre2_compile( (PCRE2_SPTR8) conf->forbidden_inputs[j].pattern, PCRE2_ZERO_TERMINATED, PCRE2_UTF, &err_code, -- 2.11.4.GIT