From e45d61af00c54231fcdc89763f1f2f6739456791 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Tue, 3 Feb 2026 12:41:06 -0500 Subject: [PATCH 1/8] Remove hybrid 5 era behavior of trying to look for a comma in a list of WHOIS nicks. This is pre rfc1450 behavior --- modules/m_whois.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/m_whois.c b/modules/m_whois.c index 1aa718e5..d2d2ad9f 100644 --- a/modules/m_whois.c +++ b/modules/m_whois.c @@ -177,13 +177,10 @@ static void do_whois(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; - char *nick; - char *p = NULL; + const char *nick; int operspy = 0; - nick = LOCAL_COPY(parv[1]); - if((p = strchr(nick, ','))) - *p = '\0'; + nick = parv[1]; if(IsOperSpy(source_p) && *nick == '!') { From 8069180afe8485b861158d22d498b260fceaeb22 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Tue, 3 Feb 2026 13:01:04 -0500 Subject: [PATCH 2/8] KICK, NAMES, TOPIC and WHOWAS still had remains of hybrid 5 behavior where it would look for a comma as if being passed a list of nicks for the parameter. This hasn't been supported by any ircd in decades, just don't treat the comma special there anymore. --- modules/core/m_kick.c | 7 ------- modules/m_knock.c | 8 ++------ modules/m_names.c | 13 ++++--------- modules/m_topic.c | 3 --- modules/m_whowas.c | 4 +--- 5 files changed, 7 insertions(+), 28 deletions(-) diff --git a/modules/core/m_kick.c b/modules/core/m_kick.c index cb655cf4..f63fe506 100644 --- a/modules/core/m_kick.c +++ b/modules/core/m_kick.c @@ -67,7 +67,6 @@ m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *p int chasing = 0; char *comment; const char *name; - char *p = NULL; const char *user; static char buf[IRCD_BUFSIZE]; @@ -75,9 +74,6 @@ m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *p flood_endgrace(source_p); *buf = '\0'; - if((p = strchr(parv[1], ','))) - *p = '\0'; - name = parv[1]; chptr = find_channel(name); @@ -135,9 +131,6 @@ m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *p */ } - if((p = strchr(parv[2], ','))) - *p = '\0'; - user = parv[2]; if(!(who = find_chasing(source_p, user, &chasing))) diff --git a/modules/m_knock.c b/modules/m_knock.c index b1185590..fb19d8a2 100644 --- a/modules/m_knock.c +++ b/modules/m_knock.c @@ -70,7 +70,7 @@ static int m_knock(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; - char *p, *name; + const char *name; if(MyClient(source_p) && ConfigChannel.use_knock == 0) { @@ -78,11 +78,7 @@ m_knock(struct Client *client_p, struct Client *source_p, int parc, const char * return 0; } - name = LOCAL_COPY(parv[1]); - - /* dont allow one knock to multiple chans */ - if((p = strchr(name, ','))) - *p = '\0'; + name = parv[1]; if(!IsChannelName(name)) { diff --git a/modules/m_names.c b/modules/m_names.c index 5e063358..fd4a71e0 100644 --- a/modules/m_names.c +++ b/modules/m_names.c @@ -68,24 +68,19 @@ m_names(struct Client *client_p, struct Client *source_p, int parc, const char * { static time_t last_used = 0; struct Channel *chptr = NULL; - char *s; if(parc > 1 && !EmptyString(parv[1])) { - char *p = LOCAL_COPY(parv[1]); - if((s = strchr(p, ','))) - *s = '\0'; - - if(!check_channel_name(p)) + if(!check_channel_name(parv[1])) { - sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), p); + sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[1]); return 0; } - if((chptr = find_channel(p)) != NULL) + if((chptr = find_channel(parv[1])) != NULL) channel_member_names(chptr, source_p, 1); else - sendto_one_numeric(source_p, s_RPL(RPL_ENDOFNAMES), p); + sendto_one_numeric(source_p, s_RPL(RPL_ENDOFNAMES), parv[1]); } else { diff --git a/modules/m_topic.c b/modules/m_topic.c index dc5605bc..b1713968 100644 --- a/modules/m_topic.c +++ b/modules/m_topic.c @@ -64,9 +64,6 @@ m_topic(struct Client *client_p, struct Client *source_p, int parc, const char * struct membership *msptr; char *p = NULL; - if((p = strchr(parv[1], ','))) - *p = '\0'; - if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); diff --git a/modules/m_whowas.c b/modules/m_whowas.c index 55c5d6ae..1f63f206 100644 --- a/modules/m_whowas.c +++ b/modules/m_whowas.c @@ -90,9 +90,7 @@ m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char return 0; #endif - nick = LOCAL_COPY(parv[1]); - if((p = strchr(nick, ','))) - *p = '\0'; + nick = parv[1]; whowas_list = whowas_get_list(nick); From 8389df1f67e141533f1ab92a2df39303e4b0315e Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Tue, 3 Feb 2026 14:40:37 -0500 Subject: [PATCH 3/8] remove outdated comment --- src/hash.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hash.c b/src/hash.c index f17f34b3..255cd5a1 100644 --- a/src/hash.c +++ b/src/hash.c @@ -153,8 +153,6 @@ fnv_hash(const unsigned char *s, unsigned int bits, size_t unused) return h; } -#if 1 /* unused currently */ - static uint32_t fnv_hash_len(const unsigned char *s, unsigned int bits, size_t len) { @@ -168,7 +166,6 @@ fnv_hash_len(const unsigned char *s, unsigned int bits, size_t len) h = (h >> (32 - bits)) ^ (h & ((1U << bits) - 1)); return h; } -#endif static uint32_t fnv_hash_upper_len(const unsigned char *s, unsigned int bits, size_t len) From 710398767c6fb385705921b21f2b8e1e7095624b Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Tue, 3 Feb 2026 15:36:28 -0500 Subject: [PATCH 4/8] Use rb_parse_time() to convert timestamps to time_t. If time_t == sizeof(long), we use atol() as we always have otherwise we use strtoimax() and hope for the best on 32bit/64bit time_t platforms. --- libratbox/include/rb_tools.h | 17 +++++++++++++++++ modules/core/m_join.c | 4 ++-- modules/core/m_mode.c | 4 ++-- modules/core/m_nick.c | 8 ++++---- modules/m_services.c | 4 ++-- modules/m_svinfo.c | 2 +- modules/m_tb.c | 2 +- 7 files changed, 29 insertions(+), 12 deletions(-) diff --git a/libratbox/include/rb_tools.h b/libratbox/include/rb_tools.h index 90810c89..ec5f318d 100644 --- a/libratbox/include/rb_tools.h +++ b/libratbox/include/rb_tools.h @@ -458,6 +458,23 @@ rb_dlinkDestroy(rb_dlink_node *node, rb_dlink_list *list) rb_free(node); } +static inline time_t +rb_parse_time(const char *s) +{ + time_t t; +#if SIZEOF_LONG == SIZEOF_TIME_T + t = (time_t)atol(s); +#else + intmax_t v; + v = strtoimax(s, NULL, 10); + t = (time_t)v; + /* make overflow clamp to 0 */ + if((intmax_t)t != v) + return 0; +#endif + return t; +} + typedef struct _rb_zstring { diff --git a/modules/core/m_join.c b/modules/core/m_join.c index 93824ddf..e03b8828 100644 --- a/modules/core/m_join.c +++ b/modules/core/m_join.c @@ -385,7 +385,7 @@ ms_join(struct Client *client_p, struct Client *source_p, int parc, const char * if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL) return 0; - newts = atol(parv[1]); + newts = rb_parse_time(parv[1]); oldts = chptr->channelts; /* making a channel TS0 */ @@ -504,7 +504,7 @@ ms_sjoin(struct Client *client_p, struct Client *source_p, int parc, const char mode.key[0] = '\0'; mode.mode = mode.limit = 0; - newts = atol(parv[1]); + newts = rb_parse_time(parv[1]); s = parv[3]; while(*s) diff --git a/modules/core/m_mode.c b/modules/core/m_mode.c index 97db9bca..9bf3f471 100644 --- a/modules/core/m_mode.c +++ b/modules/core/m_mode.c @@ -226,7 +226,7 @@ ms_tmode(struct Client *client_p, struct Client *source_p, int parc, const char } /* TS is higher, drop it. */ - if(atol(parv[1]) > chptr->channelts) + if(rb_parse_time(parv[1]) > chptr->channelts) return 0; if(IsServer(source_p)) @@ -274,7 +274,7 @@ ms_bmask(struct Client *client_p, struct Client *source_p, int parc, const char return 0; /* TS is higher, drop it. */ - if(atol(parv[1]) > chptr->channelts) + if(rb_parse_time(parv[1]) > chptr->channelts) return 0; switch (parv[3][0]) diff --git a/modules/core/m_nick.c b/modules/core/m_nick.c index da5c3a81..7e7bce0f 100644 --- a/modules/core/m_nick.c +++ b/modules/core/m_nick.c @@ -293,7 +293,7 @@ mc_nick(struct Client *client_p, struct Client *source_p, int parc, const char * return 0; } - newts = atol(parv[2]); + newts = rb_parse_time(parv[2]); target_p = find_client(parv[1]); /* if the nick doesnt exist, allow it and process like normal */ @@ -370,7 +370,7 @@ ms_nick(struct Client *client_p, struct Client *source_p, int parc, const char * */ } - newts = atol(parv[3]); + newts = rb_parse_time(parv[3]); target_p = find_client(parv[1]); @@ -415,7 +415,7 @@ ms_uid(struct Client *client_p, struct Client *source_p, int parc, const char *p struct Client *target_p; time_t newts = 0; - newts = atol(parv[3]); + newts = rb_parse_time(parv[3]); if(parc != 10) { @@ -504,7 +504,7 @@ ms_save(struct Client *client_p, struct Client *source_p, int parc, const char * sendto_realops_flags(UMODE_DEBUG, L_ALL, "Ignored noop SAVE message for %s from %s", target_p->name, source_p->name); - else if(target_p->tsinfo == atol(parv[2])) + else if(target_p->tsinfo == rb_parse_time(parv[2])) save_user(client_p, source_p, target_p); else sendto_realops_flags(UMODE_SKILL, L_ALL, diff --git a/modules/m_services.c b/modules/m_services.c index 1eb1cd7c..ad24e8b4 100644 --- a/modules/m_services.c +++ b/modules/m_services.c @@ -164,7 +164,7 @@ me_rsfnc(struct Client *client_p, struct Client *source_p, int parc, const char if(!clean_nick(parv[2])) return 0; - curts = atol(parv[4]); + curts = rb_parse_time(parv[4]); /* if tsinfo is different from what it was when services issued the * RSFNC, then we ignore it. This can happen when a client changes @@ -198,7 +198,7 @@ me_rsfnc(struct Client *client_p, struct Client *source_p, int parc, const char exit_client(NULL, exist_p, &me, buf); } - newts = atol(parv[3]); + newts = rb_parse_time(parv[3]); /* timestamp is older than 15mins, ignore it */ if(newts < (rb_current_time() - 900)) diff --git a/modules/m_svinfo.c b/modules/m_svinfo.c index 4a37568a..34df526a 100644 --- a/modules/m_svinfo.c +++ b/modules/m_svinfo.c @@ -80,7 +80,7 @@ ms_svinfo(struct Client *client_p, struct Client *source_p, int parc, const char * since we're here, might as well call rb_set_time() while we're at it */ rb_set_time(); - theirtime = atol(parv[4]); + theirtime = rb_parse_time(parv[4]); deltat = labs(theirtime - rb_current_time()); if(deltat > ConfigFileEntry.ts_max_delta) diff --git a/modules/m_tb.c b/modules/m_tb.c index c9775578..c279d84a 100644 --- a/modules/m_tb.c +++ b/modules/m_tb.c @@ -77,7 +77,7 @@ ms_tb(struct Client *client_p, struct Client *source_p, int parc, const char *pa if(chptr == NULL) return 0; - newtopicts = atol(parv[2]); + newtopicts = rb_parse_time(parv[2]); if(parc == 5) { From 48799de4ffbde268b9fd81b7781a68ce0db80970 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Tue, 3 Feb 2026 15:38:51 -0500 Subject: [PATCH 5/8] remove stray space --- libratbox/include/rb_tools.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libratbox/include/rb_tools.h b/libratbox/include/rb_tools.h index ec5f318d..b812ae86 100644 --- a/libratbox/include/rb_tools.h +++ b/libratbox/include/rb_tools.h @@ -472,7 +472,7 @@ rb_parse_time(const char *s) if((intmax_t)t != v) return 0; #endif - return t; + return t; } From 558626673dfb3eca0cc1414ae6e11fa1e95cae67 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Tue, 3 Feb 2026 16:51:57 -0500 Subject: [PATCH 6/8] Stop having smalldate() return a static variable and copy into the arguments provided --- include/s_log.h | 2 +- modules/m_dline.c | 4 ++-- modules/m_gline.c | 4 ++-- modules/m_kline.c | 4 ++-- src/s_log.c | 13 +++++++++---- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/include/s_log.h b/include/s_log.h index 150daf65..0e68c72e 100644 --- a/include/s_log.h +++ b/include/s_log.h @@ -55,6 +55,6 @@ void close_logfiles(void); void ilog(ilogfile dest, const char *fmt, ...) AFP(2, 3); void report_operspy(struct Client *, const char *, const char *); -const char *smalldate(time_t); +const char *smalldate(time_t, char *, size_t); #endif diff --git a/modules/m_dline.c b/modules/m_dline.c index c57adc32..def1c33b 100644 --- a/modules/m_dline.c +++ b/modules/m_dline.c @@ -314,7 +314,7 @@ set_dline(struct Client *source_p, const char *dlhost, const char *lreason, int { struct ConfItem *aconf; char dlbuffer[IRCD_BUFSIZE]; - const char *current_date; + char current_date[MAX_DATE_STRING]; const char *oper; char *reason; char *oper_reason; @@ -322,7 +322,7 @@ set_dline(struct Client *source_p, const char *dlhost, const char *lreason, int reason = LOCAL_COPY_N(lreason, REASONLEN); rb_set_time(); - current_date = smalldate(rb_current_time()); + smalldate(rb_current_time(), current_date, sizeof(current_date)); aconf = make_conf(); aconf->status = CONF_DLINE; diff --git a/modules/m_gline.c b/modules/m_gline.c index 3c541ce1..433e5319 100644 --- a/modules/m_gline.c +++ b/modules/m_gline.c @@ -611,11 +611,11 @@ set_local_gline(struct Client *source_p, const char *user, const char *host, con { char buffer[IRCD_BUFSIZE]; struct ConfItem *aconf; - const char *current_date; + char current_date[MAX_DATE_STRING]; char *my_reason; char *oper_reason; - current_date = smalldate(rb_current_time()); + smalldate(rb_current_time(), current_date, sizeof(current_date)); my_reason = LOCAL_COPY(reason); diff --git a/modules/m_kline.c b/modules/m_kline.c index dbfbf615..8aefdf0f 100644 --- a/modules/m_kline.c +++ b/modules/m_kline.c @@ -329,7 +329,7 @@ set_kline(struct Client *source_p, const char *user, const char *host, const cha { char buffer[IRCD_BUFSIZE]; struct ConfItem *aconf; - const char *current_date; + char current_date[MAX_DATE_STRING]; char *reason; char *oper_reason; @@ -342,7 +342,7 @@ set_kline(struct Client *source_p, const char *user, const char *host, const cha return; rb_set_time(); - current_date = smalldate(rb_current_time()); + smalldate(rb_current_time(), current_date, sizeof(current_date)); aconf = make_conf(); aconf->status = CONF_KILL; aconf->user = rb_strdup(user); diff --git a/src/s_log.c b/src/s_log.c index bbcfd692..e3e4ba34 100644 --- a/src/s_log.c +++ b/src/s_log.c @@ -172,13 +172,16 @@ ilog(ilogfile dest, const char *format, ...) FILE *logfile = *log_table[dest].logfile; char buf[IRCD_BUFSIZE]; char buf2[IRCD_BUFSIZE*2]; + char current_date[MAX_DATE_STRING]; va_list args; va_start(args, format); vsnprintf(buf, sizeof(buf), format, args); va_end(args); - snprintf(buf2, sizeof(buf2), "%s %s\n", smalldate(rb_current_time()), buf); + smalldate(rb_current_time(), current_date, sizeof(current_date)); + + snprintf(buf2, sizeof(buf2), "%s %s\n", current_date, buf); if(logfile == NULL || server_state_foreground) { fputs(buf2, stderr); @@ -215,14 +218,16 @@ report_operspy(struct Client *source_p, const char *token, const char *arg) } const char * -smalldate(time_t ltime) +smalldate(time_t ltime, char *buf, size_t bufsz) { - static char buf[MAX_DATE_STRING]; struct tm *lt; + if(buf == NULL) + return NULL; + lt = gmtime(<ime); - snprintf(buf, sizeof(buf), "%d/%d/%d %02d.%02d", + snprintf(buf, bufsz, "%d/%d/%d %02d.%02d", lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min); return buf; From 3978251cb30bf8af86357ae0ff95934b438adc92 Mon Sep 17 00:00:00 2001 From: Thomas Mannfred Carlsson Date: Wed, 4 Feb 2026 01:21:32 +0200 Subject: [PATCH 7/8] Avoid underflow when no capabs present --- src/s_serv.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/s_serv.c b/src/s_serv.c index 13e0bd02..fbbc2aa3 100644 --- a/src/s_serv.c +++ b/src/s_serv.c @@ -316,21 +316,18 @@ send_capabilities(struct Client *client_p, int cap_can_send) struct Capability *cap; char msgbuf[IRCD_BUFSIZE]; char *t; - int tl; t = msgbuf; + *t = '\0'; for(cap = captab; cap->name; ++cap) { if(cap->cap & cap_can_send) - { - tl = sprintf(t, "%s ", cap->name); - t += tl; - } + rb_snprintf_append(msgbuf, sizeof(msgbuf), "%s ", cap->name); } - t--; - *t = '\0'; + if(msgbuf[0] != '\0') + msgbuf[strlen(msgbuf) - 1] = '\0'; sendto_one(client_p, "CAPAB :%s", msgbuf); } From 08c7bb1f696c69639dfea678552ff654dfad47ca Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Tue, 3 Feb 2026 18:43:15 -0500 Subject: [PATCH 8/8] restart the resolver if rb_string_to_array gets a nothingburger --- src/dns.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/dns.c b/src/dns.c index b018ab36..d913fb8b 100644 --- a/src/dns.c +++ b/src/dns.c @@ -316,7 +316,14 @@ parse_dns_reply(rb_helper * helper) while((len = rb_helper_read(helper, dnsBuf, sizeof(dnsBuf))) > 0) { parc = rb_string_to_array(dnsBuf, parv, MAXPARA+1); - + + if(parc == 0) + { + ilog(L_MAIN, "Resolver overdosed on crack...restarting resolver"); + restart_resolver(); + return; + } + if(*parv[0] == 'R') { if(parc != 5)