diff --git a/include/h.h b/include/h.h index fa3569b0a..6b380f5a4 100644 --- a/include/h.h +++ b/include/h.h @@ -1158,6 +1158,7 @@ extern LogData *log_data_socket_error(int fd); extern LogData *log_data_link_block(ConfigItem_link *link); extern LogData *log_data_tkl(const char *key, TKL *tkl); extern LogData *log_data_tls_error(void); +extern void log_pre_rehash(void); extern int log_tests(void); extern void config_pre_run_log(void); extern void log_blocks_switchover(void); @@ -1170,6 +1171,7 @@ extern int valid_subsystem(const char *s); extern const char *timestamp_iso8601_now(void); extern const char *timestamp_iso8601(time_t v); extern int is_valid_snomask(char c); +extern int is_valid_snomask_string_testing(const char *str, char **wrong); /* end of logging */ extern void add_fake_lag(Client *client, long msec); extern char *prefix_with_extban(const char *remainder, BanContext *b, Extban *extban, char *buf, size_t buflen); diff --git a/src/conf.c b/src/conf.c index abf8068ab..f3d78dff1 100644 --- a/src/conf.c +++ b/src/conf.c @@ -246,6 +246,7 @@ MODVAR int config_error_flag = 0; int config_verbose = 0; int need_operclass_permissions_upgrade = 0; +int invalid_snomasks_encountered = 0; int have_tls_listeners = 0; char *port_6667_ip = NULL; @@ -1893,11 +1894,6 @@ void applymeblock(void) strlcpy(me.id, conf_me->sid, sizeof(me.id)); } -/** Reset config tests (before running the config test) */ -void config_test_reset(void) -{ -} - /** Run config test and all post config tests. */ int config_test_all(void) { @@ -2049,6 +2045,7 @@ int config_test(void) memset(&nicklengths, 0, sizeof(nicklengths)); config_setdefaultsettings(&tempiConf); clicap_pre_rehash(); + log_pre_rehash(); free_config_defines(); if (!config_loadmodules()) @@ -2059,8 +2056,6 @@ int config_test(void) preprocessor_resolve_conditionals_all(PREPROCESSOR_PHASE_MODULE); - config_test_reset(); - if (!config_test_all()) { config_error("IRCd configuration failed to pass testing"); @@ -2747,6 +2742,21 @@ int config_test_blocks() int errors = 0; Hook *h; + invalid_snomasks_encountered = 0; + + /* First, all the log { } blocks everywhere */ + for (cfptr = conf; cfptr; cfptr = cfptr->next) + { + if (config_verbose > 1) + config_status("Testing %s", cfptr->filename); + /* First test and run the log { } blocks */ + for (ce = cfptr->items; ce; ce = ce->next) + { + if (!strcmp(ce->name, "log")) + errors += config_test_log(cfptr, ce); + } + } + for (cfptr = conf; cfptr; cfptr = cfptr->next) { if (config_verbose > 1) @@ -2773,7 +2783,8 @@ int config_test_blocks() { /* These are already processed, so skip them here.. */ if (!strcmp(ce->name, "secret") || - !strcmp(ce->name, "set")) + !strcmp(ce->name, "set") || + !strcmp(ce->name, "log")) { continue; } @@ -2836,6 +2847,12 @@ int config_test_blocks() config_error("%i errors encountered", errors); } + if (invalid_snomasks_encountered) + { + config_error("It seems your set::snomask-on-oper and/or oper::snomask needs to be updated. Are you perhaps upgrading from an older version to UnrealIRCd 6?"); + config_error("See https://www.unrealircd.org/docs/Upgrading_from_5.x#Update_your_snomasks"); + } + return (errors > 0 ? -1 : 1); } @@ -4033,12 +4050,20 @@ int _test_oper(ConfigFile *conf, ConfigEntry *ce) /* oper::snomask */ else if (!strcmp(cep->name, "snomask")) { + char *wrong_snomask; if (has_snomask) { config_warn_duplicate(cep->file->filename, cep->line_number, "oper::snomask"); continue; } + if (!is_valid_snomask_string_testing(cep->value, &wrong_snomask)) + { + config_error("%s:%i: oper::snomask contains unknown snomask letter(s) '%s'", + cep->file->filename, cep->line_number, wrong_snomask); + errors++; + invalid_snomasks_encountered++; + } has_snomask = 1; } else if (!strcmp(cep->name, "server-notice-colors")) @@ -7808,8 +7833,16 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce) set_usermode(cep->value); } else if (!strcmp(cep->name, "snomask-on-oper")) { + char *wrong_snomask; CheckNull(cep); CheckDuplicate(cep, snomask_on_oper, "snomask-on-oper"); + if (!is_valid_snomask_string_testing(cep->value, &wrong_snomask)) + { + config_error("%s:%i: set::snomask-on-oper contains unknown snomask letter(s) '%s'", + cep->file->filename, cep->line_number, wrong_snomask); + errors++; + invalid_snomasks_encountered++; + } } else if (!strcmp(cep->name, "server-notice-colors")) { CheckNull(cep); diff --git a/src/log.c b/src/log.c index c3585684b..d21dabbca 100644 --- a/src/log.c +++ b/src/log.c @@ -36,6 +36,7 @@ Log *temp_logs[NUM_LOG_DESTINATIONS] = { NULL, NULL, NULL, NULL, NULL }; static int snomask_num_destinations = 0; static char snomasks_in_use[257] = { '\0' }; +static char snomasks_in_use_testing[257] = { '\0' }; /* Forward declarations */ int log_sources_match(LogSource *logsource, LogLevel loglevel, const char *subsystem, const char *event_id, int matched_already); @@ -205,6 +206,8 @@ int config_test_log(ConfigFile *conf, ConfigEntry *block) config_error("%s:%d: snomask must be a single letter", cep->file->filename, cep->line_number); errors++; + } else { + strlcat(snomasks_in_use_testing, cep->value, sizeof(snomasks_in_use_testing)); } } else if (!strcmp(cep->name, "channel")) @@ -1803,6 +1806,12 @@ void postconf_defaults_log_block(void) AppendListItem(ls, l->sources); } +/* Called before CONFIG_TEST */ +void log_pre_rehash(void) +{ + *snomasks_in_use_testing = '\0'; +} + /* Called after CONFIG_TEST right before CONFIG_RUN */ void config_pre_run_log(void) { @@ -1828,3 +1837,35 @@ int is_valid_snomask(char c) { return strchr(snomasks_in_use, c) ? 1 : 0; } + +/** Check if a letter is a valid snomask during or after CONFIG_TEST + * (the snomasks exist in the log block configuration read during config_test). + * @param c the snomask letter to check + * @returns 1 if exists, 0 if not. + */ +int is_valid_snomask_testing(char c) +{ + return strchr(snomasks_in_use_testing, c) ? 1 : 0; +} + +/** Check if a string all consists of valid snomasks during or after CONFIG_TEST + * (the snomasks exist in the log block configuration read during config_test). + * @param str the snomask string to check + * @param invalid_snomasks list of unknown snomask letters + * @returns 1 if exists, 0 if not. + */ +int is_valid_snomask_string_testing(const char *str, char **invalid_snomasks) +{ + static char invalid_snomasks_buf[256]; + + *invalid_snomasks_buf = '\0'; + for (; *str; str++) + { + if ((*str == '+') || (*str == '-')) + continue; + if (!strchr(snomasks_in_use_testing, *str)) + strlcat_letter(invalid_snomasks_buf, *str, sizeof(invalid_snomasks_buf)); + } + *invalid_snomasks = invalid_snomasks_buf; + return *invalid_snomasks_buf ? 0 : 1; +}