mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-07-04 08:03:12 +02:00
704487e124
In 3.2.x we didn't fix these bugs since servers are trusted and should send correct commands. In 4.0.x we changed this so we would fix them when we come across such issues at normal priority (not consider them security issues). I now took it a step further and actively checked/looked for these issues and a bunch of them were found. Almost all are NULL pointer dereferences, with some exceptions. * S2S: MODE: check conv_param return value (NULL ptr crash) * S2S: MODE: floodprot: More checks (NULL ptr crash) * S2S: MODE: OOB write of NULL (write NULL past last element in an array) * S2S: NICK: old compat fixes (NULL ptr crash) * S2S: PROTOCTL: Check for double SID= * S2S: SERVER: require at least 3 parameters (NULL ptr crash) * S2S: SJOIN: require at least 3 parameters (NULL ptr crash) * S2S: SJOIN: Fix OOB read (read 1 byte past buffer) * S2S: TKL: validate set_at and expire_at (NULL ptr crash) * S2S: TKL: require at least 9 parameters for spamf, not 8 (NULL ptr crash) * S2S: TKL: ignore invalid spamfilter matching type (remove abort() call) * S2S: TOPIC: querying for topic is not permitted (NULL ptr crash) * S2S: UID: require 12 parameters (NULL ptr crash) * S2S: WATCH: this is not a server command (NULL ptr crash) * Fix OOB read (1 byte beyond string) for timevals. This was reachable from config code, TKL (S2S) and /*LINE (Oper). In practice no crash. * MODE: make code less confusing (effectively no change) * TRACE: remove strange output in case of 0 lines of output * Fix unimportant memory leak on boot (#4713, reported by dg) * Fix small memory leak upon 'DNS i' (oper only command) * Always work on a copy in clean_ban_mask(). This fixes a bug that could result in a strlcpy(buf, buf, sizeof(buf)). So, overlapping strings, which is undefined behavior.
283 lines
6.3 KiB
C
283 lines
6.3 KiB
C
/*
|
|
* IRC - Internet Relay Chat, src/modules/m_watch.c
|
|
* (C) 2005 The UnrealIRCd Team
|
|
*
|
|
* See file AUTHORS in IRC package for additional names of
|
|
* the programmers.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 1, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "unrealircd.h"
|
|
|
|
CMD_FUNC(m_watch);
|
|
|
|
#define MSG_WATCH "WATCH"
|
|
|
|
ModuleHeader MOD_HEADER(m_watch)
|
|
= {
|
|
"m_watch",
|
|
"4.0",
|
|
"command /watch",
|
|
"3.2-b8-1",
|
|
NULL
|
|
};
|
|
|
|
MOD_INIT(m_watch)
|
|
{
|
|
CommandAdd(modinfo->handle, MSG_WATCH, m_watch, 1, M_USER);
|
|
MARK_AS_OFFICIAL_MODULE(modinfo);
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
MOD_LOAD(m_watch)
|
|
{
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
MOD_UNLOAD(m_watch)
|
|
{
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* RPL_NOWON - Online at the moment (Successfully added to WATCH-list)
|
|
* RPL_NOWOFF - Offline at the moement (Successfully added to WATCH-list)
|
|
* RPL_WATCHOFF - Successfully removed from WATCH-list.
|
|
* ERR_TOOMANYWATCH - Take a guess :> Too many WATCH entries.
|
|
*/
|
|
static void show_watch(aClient *cptr, char *name, int rpl1, int rpl2, int awaynotify)
|
|
{
|
|
aClient *acptr;
|
|
|
|
|
|
if ((acptr = find_person(name, NULL)))
|
|
{
|
|
if (awaynotify && acptr->user->away)
|
|
{
|
|
sendto_one(cptr, rpl_str(RPL_NOWISAWAY), me.name, cptr->name,
|
|
acptr->name, acptr->user->username,
|
|
IsHidden(acptr) ? acptr->user->virthost : acptr->user->
|
|
realhost, acptr->user->lastaway);
|
|
return;
|
|
}
|
|
|
|
sendto_one(cptr, rpl_str(rpl1), me.name, cptr->name,
|
|
acptr->name, acptr->user->username,
|
|
IsHidden(acptr) ? acptr->user->virthost : acptr->user->
|
|
realhost, acptr->lastnick);
|
|
}
|
|
else
|
|
{
|
|
sendto_one(cptr, rpl_str(rpl2), me.name, cptr->name,
|
|
name, "*", "*", 0L);
|
|
}
|
|
}
|
|
|
|
static char buf[BUFSIZE];
|
|
|
|
/*
|
|
* m_watch
|
|
*/
|
|
CMD_FUNC(m_watch)
|
|
{
|
|
aClient *acptr;
|
|
char *s, **pav = parv, *user;
|
|
char *p = NULL, *def = "l";
|
|
int awaynotify = 0;
|
|
int did_l=0, did_s=0;
|
|
|
|
if (parc < 2)
|
|
{
|
|
/*
|
|
* Default to 'l' - list who's currently online
|
|
*/
|
|
parc = 2;
|
|
parv[1] = def;
|
|
}
|
|
|
|
for (s = (char *)strtoken(&p, *++pav, " "); s;
|
|
s = (char *)strtoken(&p, NULL, " "))
|
|
{
|
|
if ((user = (char *)index(s, '!')))
|
|
*user++ = '\0'; /* Not used */
|
|
|
|
if (!strcmp(s, "A") && WATCH_AWAY_NOTIFICATION)
|
|
awaynotify = 1;
|
|
|
|
/*
|
|
* Prefix of "+", they want to add a name to their WATCH
|
|
* list.
|
|
*/
|
|
if (*s == '+')
|
|
{
|
|
if (!*(s+1))
|
|
continue;
|
|
if (do_nick_name(s + 1))
|
|
{
|
|
if (sptr->local->watches >= MAXWATCH)
|
|
{
|
|
sendto_one(sptr,
|
|
err_str(ERR_TOOMANYWATCH), me.name,
|
|
cptr->name, s + 1);
|
|
|
|
continue;
|
|
}
|
|
|
|
add_to_watch_hash_table(s + 1, sptr, awaynotify);
|
|
}
|
|
|
|
show_watch(sptr, s + 1, RPL_NOWON, RPL_NOWOFF, awaynotify);
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Prefix of "-", coward wants to remove somebody from their
|
|
* WATCH list. So do it. :-)
|
|
*/
|
|
if (*s == '-')
|
|
{
|
|
if (!*(s+1))
|
|
continue;
|
|
del_from_watch_hash_table(s + 1, sptr);
|
|
show_watch(sptr, s + 1, RPL_WATCHOFF, RPL_WATCHOFF, 0);
|
|
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Fancy "C" or "c", they want to nuke their WATCH list and start
|
|
* over, so be it.
|
|
*/
|
|
if (*s == 'C' || *s == 'c')
|
|
{
|
|
hash_del_watch_list(sptr);
|
|
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Now comes the fun stuff, "S" or "s" returns a status report of
|
|
* their WATCH list. I imagine this could be CPU intensive if its
|
|
* done alot, perhaps an auto-lag on this?
|
|
*/
|
|
if ((*s == 'S' || *s == 's') && !did_s)
|
|
{
|
|
Link *lp;
|
|
aWatch *anptr;
|
|
int count = 0;
|
|
|
|
did_s = 1;
|
|
|
|
/*
|
|
* Send a list of how many users they have on their WATCH list
|
|
* and how many WATCH lists they are on.
|
|
*/
|
|
anptr = hash_get_watch(sptr->name);
|
|
if (anptr)
|
|
for (lp = anptr->watch, count = 1;
|
|
(lp = lp->next); count++)
|
|
;
|
|
sendto_one(sptr, rpl_str(RPL_WATCHSTAT), me.name,
|
|
sptr->name, sptr->local->watches, count);
|
|
|
|
/*
|
|
* Send a list of everybody in their WATCH list. Be careful
|
|
* not to buffer overflow.
|
|
*/
|
|
if ((lp = sptr->local->watch) == NULL)
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST),
|
|
me.name, sptr->name, *s);
|
|
continue;
|
|
}
|
|
*buf = '\0';
|
|
strlcpy(buf, lp->value.wptr->nick, sizeof buf);
|
|
count =
|
|
strlen(sptr->name) + strlen(me.name) + 10 +
|
|
strlen(buf);
|
|
while ((lp = lp->next))
|
|
{
|
|
if (count + strlen(lp->value.wptr->nick) + 1 >
|
|
BUFSIZE - 2)
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_WATCHLIST),
|
|
me.name, sptr->name, buf);
|
|
*buf = '\0';
|
|
count =
|
|
strlen(sptr->name) + strlen(me.name) +
|
|
10;
|
|
}
|
|
strcat(buf, " ");
|
|
strcat(buf, lp->value.wptr->nick);
|
|
count += (strlen(lp->value.wptr->nick) + 1);
|
|
}
|
|
sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name,
|
|
sptr->name, buf);
|
|
|
|
sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name,
|
|
sptr->name, *s);
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Well that was fun, NOT. Now they want a list of everybody in
|
|
* their WATCH list AND if they are online or offline? Sheesh,
|
|
* greedy arn't we?
|
|
*/
|
|
if ((*s == 'L' || *s == 'l') && !did_l)
|
|
{
|
|
Link *lp = sptr->local->watch;
|
|
|
|
did_l = 1;
|
|
|
|
while (lp)
|
|
{
|
|
if ((acptr =
|
|
find_person(lp->value.wptr->nick, NULL)))
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_NOWON),
|
|
me.name, sptr->name, acptr->name,
|
|
acptr->user->username,
|
|
IsHidden(acptr) ? acptr->user->
|
|
virthost : acptr->user->realhost,
|
|
acptr->lastnick);
|
|
}
|
|
/*
|
|
* But actually, only show them offline if its a capital
|
|
* 'L' (full list wanted).
|
|
*/
|
|
else if (isupper(*s))
|
|
sendto_one(sptr, rpl_str(RPL_NOWOFF),
|
|
me.name, sptr->name,
|
|
lp->value.wptr->nick, "*", "*",
|
|
lp->value.wptr->lasttime);
|
|
lp = lp->next;
|
|
}
|
|
|
|
sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name,
|
|
sptr->name, *s);
|
|
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Hmm.. unknown prefix character.. Ignore it. :-)
|
|
*/
|
|
}
|
|
|
|
return 0;
|
|
}
|