1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-30 12:26:37 +02:00
Files
unrealircd/src/modules/kill.c
T
Bram Matthys 4ac8015f84 Remove 'cptr' from all commands, hooks, etc. It only confuses people and
'sptr' is sufficient and in most cases the only one you should care about.
Should you need it, you can access sptr->direction in cases where you
need the old information (usually only for some sendto_* functions
and some protoctl checks), so 'cptr' was redundant too.

[!] This change likely introduces some bugs. This was many hours of work.
I only cut some corners in 4 functions, which will be fixed at a later
stage..... yes, more major changes to come.

On the plus side, I likely fixed some bugs in the process. Situations
where cptr vs sptr usage was incorrect. Eg using cptr->name (near server)
when sptr->name should be used (the actual source server), etc....
2019-10-02 14:25:40 +02:00

269 lines
7.4 KiB
C

/*
* Unreal Internet Relay Chat Daemon, src/modules/kill.c
* (C) 2000-2001 Carsten V. Munk and the UnrealIRCd Team
* Moved to modules by Fish (Justin Hammond)
*
* 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(cmd_kill);
static char buf[BUFSIZE], buf2[BUFSIZE];
/* Place includes here */
#define MSG_KILL "KILL" /* KILL */
ModuleHeader MOD_HEADER
= {
"kill", /* Name of module */
"5.0", /* Version */
"command /kill", /* Short description of module */
"UnrealIRCd Team",
"unrealircd-5",
};
/* This is called on module init, before Server Ready */
MOD_INIT()
{
CommandAdd(modinfo->handle, MSG_KILL, cmd_kill, 2, CMD_USER|CMD_SERVER);
MARK_AS_OFFICIAL_MODULE(modinfo);
return MOD_SUCCESS;
}
/* Is first run when server is 100% ready */
MOD_LOAD()
{
return MOD_SUCCESS;
}
/* Called when module is unloaded */
MOD_UNLOAD()
{
return MOD_SUCCESS;
}
/*
** cmd_kill
** parv[1] = kill victim(s) - comma separated list
** parv[2] = kill path
*/
CMD_FUNC(cmd_kill)
{
Client *acptr;
char inpath[HOSTLEN * 2 + USERLEN + 5];
char *oinpath = get_client_name(sptr->direction, FALSE);
char *user, *path, *killer, *nick, *p, *s;
int kcount = 0;
Hook *h;
int ntargets = 0, n;
int maxtargets = max_targets_for_command("KILL");
if (parc < 2 || *parv[1] == '\0')
{
sendnumeric(sptr, ERR_NEEDMOREPARAMS, "KILL");
return 0;
}
// FIXME: clean all this killpath shit, nobody cares anymore these days.
// FYI, I just replaced 'cptr' with 'sptr->direction' for now, but
// we should clean up this mess later, see the FIXME.
user = parv[1];
path = parv[2]; /* Either defined or NULL (parc >= 2!!) */
strlcpy(inpath, oinpath, sizeof inpath);
if (IsServer(sptr->direction) && (s = strchr(inpath, '.')) != NULL)
*s = '\0'; /* Truncate at first "." -- hmm... why ? */
if (!IsServer(sptr->direction) && !ValidatePermissionsForPath("kill:global",sptr,NULL,NULL,NULL) && !ValidatePermissionsForPath("kill:local",sptr,NULL,NULL,NULL))
{
sendnumeric(sptr, ERR_NOPRIVILEGES);
return 0;
}
if (BadPtr(path))
{
sendnumeric(sptr, ERR_NEEDMOREPARAMS, "KILL");
return 0;
}
if (strlen(path) > iConf.quit_length)
path[iConf.quit_length] = '\0';
if (MyUser(sptr))
user = canonize(user);
for (p = NULL, nick = strtoken(&p, user, ","); nick; nick = strtoken(&p, NULL, ","))
{
MessageTag *mtags = NULL;
if (MyUser(sptr) && (++ntargets > maxtargets))
{
sendnumeric(sptr, ERR_TOOMANYTARGETS, nick, maxtargets, "KILL");
break;
}
acptr = find_person(nick, NULL);
/* If a local user issued the /KILL then we will "chase" the user.
* In other words: we'll check the history for recently changed nicks.
* We don't do this for remote KILL requests as we have UID for that.
*/
if (!acptr && MyUser(sptr))
{
acptr = get_history(nick, KILLCHASETIMELIMIT);
if (acptr)
sendnotice(sptr, "*** KILL changed from %s to %s", nick, acptr->name);
}
if (!acptr)
{
sendnumeric(sptr, ERR_NOSUCHNICK, nick);
continue;
}
if ((!MyConnect(acptr) && MyUser(sptr) && !ValidatePermissionsForPath("kill:global",sptr,acptr,NULL,NULL))
|| (MyConnect(acptr) && MyUser(sptr)
&& !ValidatePermissionsForPath("kill:local",sptr,acptr,NULL,NULL)))
{
sendnumeric(sptr, ERR_NOPRIVILEGES);
continue;
}
/* Hooks can plug-in here to reject a kill */
if (MyUser(sptr))
{
int ret = EX_ALLOW;
for (h = Hooks[HOOKTYPE_PRE_KILL]; h; h = h->next)
{
/* note: parameters are: sptr, victim, reason. reason can be NULL !! */
ret = (*(h->func.intfunc))(sptr, acptr, path);
if (ret != EX_ALLOW)
break;
}
if ((ret == EX_DENY) || (ret == EX_ALWAYS_DENY))
continue; /* reject kill for this particular user */
}
/* From here on, the kill is probably going to be successful. */
kcount++;
if (!IsServer(sptr) && (kcount > MAXKILLS))
{
sendnotice(sptr,
"*** Too many targets, kill list was truncated. Maximum is %d.",
MAXKILLS);
break;
}
if (!IsServer(sptr->direction))
{
/*
** The kill originates from this server, initialize path.
** (In which case the 'path' may contain user suplied
** explanation ...or some nasty comment, sigh... >;-)
**
** ...!operhost!oper
** ...!operhost!oper (comment)
*/
strlcpy(inpath, GetHost(sptr->direction), sizeof inpath);
if (kcount == 1)
{
ircsnprintf(buf, sizeof(buf), "%s (%s)", sptr->direction->name, path);
path = buf;
}
}
/*
** Notify all *local* opers about the KILL (this includes the one
** originating the kill, if from this server--the special numeric
** reply message is not generated anymore).
**
** Note: "acptr->name" is used instead of "user" because we may
** have changed the target because of the nickname change.
*/
sendto_snomask(SNO_KILLS,
"*** Received KILL message for %s!%s@%s from %s Path: %s!%s",
acptr->name, acptr->user->username,
IsHidden(acptr) ? acptr->user->virthost : acptr->user->realhost,
sptr->name, inpath, path);
ircd_log(LOG_KILL, "KILL (%s) by %s(%s!%s)",
make_nick_user_host(acptr->name, acptr->user->username, GetHost(acptr)),
sptr->name, inpath, path);
new_message(sptr, recv_mtags, &mtags);
/* Victim gets a little notification (s)he is about to die */
if (MyConnect(acptr))
{
sendto_prefix_one(acptr, sptr, NULL, ":%s KILL %s :%s!%s",
sptr->name, acptr->name, inpath, path);
}
if (MyConnect(acptr) && MyConnect(sptr))
{
/* Local kill. This is handled as if it were a QUIT */
/* Prepare buffer for exit_client */
ircsnprintf(buf2, sizeof(buf2), "[%s] Local kill by %s (%s)",
me.name, sptr->name,
BadPtr(parv[2]) ? sptr->name : parv[2]);
}
else
{
/* Kill from one server to another (we may be src, victim or something in-between) */
/* Broadcast it to other SID and non-SID servers (may be a NOOP, obviously) */
sendto_server(sptr, PROTO_SID, 0, mtags, ":%s KILL %s :%s!%s",
sptr->name, ID(acptr), inpath, path);
sendto_server(sptr, 0, PROTO_SID, mtags, ":%s KILL %s :%s!%s",
sptr->name, acptr->name, inpath, path);
/* Don't send a QUIT for this */
SetKilled(acptr);
/* Prepare the buffer for exit_client */
if ((killer = strchr(path, ' ')))
{
while ((killer >= path) && *killer && *killer != '!')
killer--;
if (!*killer)
killer = path;
else
killer++;
}
else
killer = path;
ircsnprintf(buf2, sizeof(buf2), "Killed (%s)", killer);
}
if (MyUser(sptr))
RunHook3(HOOKTYPE_LOCAL_KILL, sptr, acptr, parv[2]);
n = exit_client(sptr->direction, acptr, sptr, mtags, buf2);
free_message_tags(mtags);
if ((n == FLUSH_BUFFER) && (sptr == acptr))
return FLUSH_BUFFER; /* return if we killed ourselves */
}
return 0;
}