From 9cc2918d5fec7928606eaa284b8eabc0f11776d3 Mon Sep 17 00:00:00 2001 From: Bram Matthys Date: Sat, 6 Jul 2024 09:59:35 +0200 Subject: [PATCH] Make set::spamfilter::except a Mask item * [set::spamfilter::except](https://www.unrealircd.org/docs/Set_block#set::spamfilter::except) is now a [Mask item](https://www.unrealircd.org/docs/Mask_item) instead of only a list of exempted targets. A warning is created to existing users along with a suggestion of how to use the new syntax. Technically, this is not really new functionality as all this was already possible via the [Except ban block](https://www.unrealircd.org/docs/Except_ban_block) with type spamfilter, but it is more visible/logical to have this also. --- doc/RELEASE-NOTES.md | 7 ++++++ include/dynconf.h | 2 +- src/conf.c | 51 +++++++++++++++++++++++++------------------- src/modules/tkl.c | 24 ++++----------------- 4 files changed, 41 insertions(+), 43 deletions(-) diff --git a/doc/RELEASE-NOTES.md b/doc/RELEASE-NOTES.md index 287f0c523..4b343a2e3 100644 --- a/doc/RELEASE-NOTES.md +++ b/doc/RELEASE-NOTES.md @@ -27,6 +27,13 @@ in progress and may not always be a stable version. We normally show the nickname of the oper who did the /KILL in the quit message. When set to `yes` the quit message becomes shortened to "Killed (Reason)". This can prevent oper harassment. +* [set::spamfilter::except](https://www.unrealircd.org/docs/Set_block#set::spamfilter::except) + is now a [Mask item](https://www.unrealircd.org/docs/Mask_item) instead of + only a list of exempted targets. A warning is created to existing users + along with a suggestion of how to use the new syntax. Technically, this is + not really new functionality as all this was already possible via + the [Except ban block](https://www.unrealircd.org/docs/Except_ban_block) + with type spamfilter, but it is more visible/logical to have this also. ### Changes: * IRCOps with the operclass `locop` can now only `REHASH` the local server diff --git a/include/dynconf.h b/include/dynconf.h index 65ce80e1a..17dc8ddf2 100644 --- a/include/dynconf.h +++ b/include/dynconf.h @@ -122,7 +122,7 @@ struct Configuration { char *spamfilter_ban_reason; char *spamfilter_virus_help_channel; char spamfilter_vchan_deny; - SpamExcept *spamexcept; + SecurityGroup *spamfilter_except; char *spamexcept_line; long spamfilter_detectslow_warn; long spamfilter_detectslow_fatal; diff --git a/src/conf.c b/src/conf.c index 7a8a5b473..1adc009ff 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1674,7 +1674,7 @@ void free_iConf(Configuration *i) safe_free(i->level_on_join); safe_free(i->spamfilter_ban_reason); safe_free(i->spamfilter_virus_help_channel); - // spamexcept is freed elsewhere + safe_free_security_group(i->spamfilter_except); safe_free(i->spamexcept_line); safe_free(i->reject_message_too_many_connections); safe_free(i->reject_message_server_full); @@ -2465,7 +2465,6 @@ void config_rehash() ConfigItem_sni *sni; OperStat *os_ptr; ListStruct *next, *next2; - SpamExcept *spamex_ptr; USE_BAN_VERSION = 0; @@ -2690,12 +2689,6 @@ void config_rehash() safe_free(os_ptr); } iConf.allow_user_stats_ext = NULL; - for (spamex_ptr = iConf.spamexcept; spamex_ptr; spamex_ptr = (SpamExcept *)next) - { - next = (ListStruct *)spamex_ptr->next; - safe_free(spamex_ptr); - } - iConf.spamexcept = NULL; for (of_ptr = conf_offchans; of_ptr; of_ptr = (ConfigItem_offchans *)next) { next = (ListStruct *)of_ptr->next; @@ -8203,19 +8196,20 @@ int _conf_set(ConfigFile *conf, ConfigEntry *ce) tempiConf.spamfilter_vchan_deny = config_checkval(cepp->value,CFG_YESNO); else if (!strcmp(cepp->name, "except")) { - char *name, *p; - SpamExcept *e; - safe_strdup(tempiConf.spamexcept_line, cepp->value); - for (name = strtoken(&p, cepp->value, ","); name; name = strtoken(&p, NULL, ",")) + if (cepp->value && !tempiConf.spamfilter_except) { - if (*name == ' ') - name++; - if (*name) + /* OLD set::spamfilter::except compatibility code when it was "#chan,xyz" */ + char buf[512], *p = NULL, *name; + strlcpy(buf, cepp->value, sizeof(buf)); + tempiConf.spamfilter_except = safe_alloc(sizeof(SecurityGroup)); + for (name = strtoken(&p, buf, ","); name; name = strtoken(&p, NULL, ",")) { - e = safe_alloc(sizeof(SpamExcept) + strlen(name)); - strcpy(e->name, name); - AddListItem(e, tempiConf.spamexcept); + skip_whitespace(&name); + add_name_list(tempiConf.spamfilter_except->destination, name); } + } else { + /* New set::spamfilter::except code, where it is a mask item */ + conf_match_block(conf, cepp, &tempiConf.spamfilter_except); } } else if (!strcmp(cepp->name, "detect-slow-warn")) @@ -9356,6 +9350,23 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce) else if (!strcmp(cep->name, "spamfilter")) { for (cepp = cep->items; cepp; cepp = cepp->next) { + if (!strcmp(cepp->name, "except")) + { + if (cepp->value) + { + /* Old compatibility code */ + config_warn("%s: %d: set::spamfilter::except is now a mask item. " + "Your setting has been read correctly but please update your item " + "because future UnrealIRCd versions will make this an error. " + "Update your item to use this style: " + "except { destination { \"#chan1\"; \"#chan2\"; \"SomeNick\"; } }", + cepp->file->filename, cepp->line_number); + config_warn("For more information, see https://www.unrealircd.org/docs/Set_block#set::spamfilter::except"); + } else { + test_match_block(conf, cepp, &errors); + } + continue; // needed, because we are above the CheckNull and the multiple if's below. + } CheckNull(cepp); if (!strcmp(cepp->name, "ban-time")) { @@ -9392,10 +9403,6 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce) { CheckDuplicate(cepp, spamfilter_virus_help_channel_deny, "spamfilter::virus-help-channel-deny"); } else - if (!strcmp(cepp->name, "except")) - { - CheckDuplicate(cepp, spamfilter_except, "spamfilter::except"); - } else #ifdef SPAMFILTER_DETECTSLOW if (!strcmp(cepp->name, "detect-slow-warn")) { diff --git a/src/modules/tkl.c b/src/modules/tkl.c index cf2b5a1c1..4f26639b0 100644 --- a/src/modules/tkl.c +++ b/src/modules/tkl.c @@ -5167,21 +5167,6 @@ TKL *choose_winning_spamfilter(TKL *one, TKL *two) return (one->ptr.spamfilter->target > two->ptr.spamfilter->target) ? one : two; } -/** Checks if 'target' is on the spamfilter exception list. - * RETURNS 1 if found in list, 0 if not. - */ -static int target_is_spamexcept(const char *target) -{ - SpamExcept *e; - - for (e = iConf.spamexcept; e; e = e->next) - { - if (match_simple(e->name, target)) - return 1; - } - return 0; -} - /** Make user join the virus channel. * @param client The user that was doing something bad. * @param tk The TKL entry that matched this user. @@ -5273,10 +5258,6 @@ static void match_spamfilter_hit(Client *client, const char *str_in, const char int stopped; int highest_action; - /* Perhaps it's on the exceptions list? */ - if (!*winner_tkl && destination && target_is_spamexcept(destination)) - return; /* No problem! */ - if (match_spamfilter_exempt(tkl, user_is_exempt_general, user_is_exempt_central)) { tkl->ptr.spamfilter->hits_except++; @@ -5389,8 +5370,11 @@ int _match_spamfilter(Client *client, const char *str_in, int target, const char /* Client exempt from spamfilter checking? * Let's check that early: going through elines is likely faster than running the regex(es). */ - if (find_tkl_exception(TKL_SPAMF, client)) + if (find_tkl_exception(TKL_SPAMF, client) || + (iConf.spamfilter_except && user_allowed_by_security_group_context(client, iConf.spamfilter_except, &context))) + { user_is_exempt_general = 1; + } if (user_allowed_by_security_group_context(client, iConf.central_spamfilter_except, &context)) user_is_exempt_central = 1;