New function IRC_KillClient() to kill clients

The old local function Kill_Nick() in irc.c has been an ugly hack. This
patch implements a generic function for killing clients.

Adjust all callers of Kill_Nick() and respect the return code!
This commit is contained in:
Alexander Barton 2013-10-01 12:13:17 +02:00
parent cccd8fc957
commit b5faf3055b
3 changed files with 105 additions and 101 deletions

View File

@ -1,6 +1,6 @@
/*
* ngIRCd -- The Next Generation IRC Daemon
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
* Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
*
* 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
@ -39,7 +39,6 @@
#include "exp.h"
#include "irc-login.h"
static void Kill_Nick PARAMS((char *Nick, char *Reason));
static void Change_Nick PARAMS((CLIENT * Origin, CLIENT * Target, char *NewNick,
bool InformClient));
@ -303,17 +302,21 @@ IRC_NICK( CLIENT *Client, REQUEST *Req )
* the new nick is already present on this server:
* the new and the old one have to be disconnected now.
*/
Log( LOG_ERR, "Server %s introduces already registered nick \"%s\"!", Client_ID( Client ), Req->argv[0] );
Kill_Nick( Req->argv[0], "Nick collision" );
return CONNECTED;
Log(LOG_ERR,
"Server %s introduces already registered nick \"%s\"!",
Client_ID(Client), Req->argv[0]);
return IRC_KillClient(Client, NULL, Req->argv[0],
"Nick collision");
}
/* Find the Server this client is connected to */
intr_c = Client_GetFromToken(Client, token);
if (!intr_c) {
Log( LOG_ERR, "Server %s introduces nick \"%s\" on unknown server!?", Client_ID( Client ), Req->argv[0] );
Kill_Nick( Req->argv[0], "Unknown server" );
return CONNECTED;
Log(LOG_ERR,
"Server %s introduces nick \"%s\" on unknown server!?",
Client_ID(Client), Req->argv[0]);
return IRC_KillClient(Client, NULL, Req->argv[0],
"Unknown server");
}
c = Client_NewRemoteUser(intr_c, nick, hops, user, hostname,
@ -324,8 +327,8 @@ IRC_NICK( CLIENT *Client, REQUEST *Req )
Log(LOG_ALERT,
"Can't create client structure! (on connection %d)",
Client_Conn(Client));
Kill_Nick(Req->argv[0], "Server error");
return CONNECTED;
return IRC_KillClient(Client, NULL, Req->argv[0],
"Server error");
}
/* RFC 2813: client is now fully registered, inform all the
@ -536,19 +539,19 @@ IRC_SERVICE(CLIENT *Client, REQUEST *Req)
c = Client_Search(nick);
if(c) {
/* Nickname collision: disconnect (KILL) both clients! */
Log(LOG_ERR, "Server %s introduces already registered service \"%s\"!",
Log(LOG_ERR,
"Server %s introduces already registered service \"%s\"!",
Client_ID(Client), nick);
Kill_Nick(nick, "Nick collision");
return CONNECTED;
return IRC_KillClient(Client, NULL, nick, "Nick collision");
}
/* Get the server to which the service is connected */
intr_c = Client_GetFromToken(Client, token);
if (! intr_c) {
Log(LOG_ERR, "Server %s introduces service \"%s\" on unknown server!?",
Log(LOG_ERR,
"Server %s introduces service \"%s\" on unknown server!?",
Client_ID(Client), nick);
Kill_Nick(nick, "Unknown server");
return CONNECTED;
return IRC_KillClient(Client, NULL, nick, "Unknown server");
}
/* Get user and host name */
@ -577,10 +580,10 @@ IRC_SERVICE(CLIENT *Client, REQUEST *Req)
if (! c) {
/* Couldn't create client structure, so KILL the service to
* keep network status consistent ... */
Log(LOG_ALERT, "Can't create client structure! (on connection %d)",
Log(LOG_ALERT,
"Can't create client structure! (on connection %d)",
Client_Conn(Client));
Kill_Nick(nick, "Server error");
return CONNECTED;
return IRC_KillClient(Client, NULL, nick, "Server error");
}
Client_Introduce(Client, c, CLIENT_SERVICE);
@ -855,31 +858,6 @@ IRC_PONG(CLIENT *Client, REQUEST *Req)
return CONNECTED;
} /* IRC_PONG */
/**
* Kill all users with a specific nickname in the network.
*
* @param Nick Nickname.
* @param Reason Reason for the KILL.
*/
static void
Kill_Nick(char *Nick, char *Reason)
{
REQUEST r;
assert (Nick != NULL);
assert (Reason != NULL);
r.prefix = NULL;
r.argv[0] = Nick;
r.argv[1] = Reason;
r.argc = 2;
Log(LOG_ERR, "User(s) with nick \"%s\" will be disconnected: %s!",
Nick, Reason);
IRC_KILL(Client_ThisServer(), &r);
} /* Kill_Nick */
/**
* Change the nickname of a client.
*

View File

@ -128,9 +128,8 @@ IRC_ERROR(CLIENT *Client, REQUEST *Req)
GLOBAL bool
IRC_KILL(CLIENT *Client, REQUEST *Req)
{
CLIENT *prefix, *c;
char reason[COMMAND_LEN], *msg;
CONN_ID my_conn, conn;
CLIENT *prefix;
char reason[COMMAND_LEN];
assert (Client != NULL);
assert (Req != NULL);
@ -166,59 +165,8 @@ IRC_KILL(CLIENT *Client, REQUEST *Req)
else
strlcpy(reason, Req->argv[1], sizeof(reason));
/* Inform other servers */
IRC_WriteStrServersPrefix(Client, prefix, "KILL %s :%s",
Req->argv[0], reason);
/* Save ID of this connection */
my_conn = Client_Conn( Client );
/* Do we host such a client? */
c = Client_Search( Req->argv[0] );
if (c) {
if (Client_Type(c) != CLIENT_USER
&& Client_Type(c) != CLIENT_GOTNICK) {
/* Target of this KILL is not a regular user, this is
* invalid! So we ignore this case if we received a
* regular KILL from the network and try to kill the
* client/connection anyway (but log an error!) if the
* origin is the local server. */
if (Client != Client_ThisServer()) {
/* Invalid KILL received from remote */
if (Client_Type(c) == CLIENT_SERVER)
msg = ERR_CANTKILLSERVER_MSG;
else
msg = ERR_NOPRIVILEGES_MSG;
return IRC_WriteErrClient(Client, msg,
Client_ID(Client));
}
Log(LOG_ERR,
"Got KILL for invalid client type: %d, \"%s\"!",
Client_Type( c ), Req->argv[0] );
}
/* Kill the client NOW:
* - Close the local connection (if there is one),
* - Destroy the CLIENT structure for remote clients.
* Note: Conn_Close() removes the CLIENT structure as well. */
conn = Client_Conn( c );
if(conn > NONE)
Conn_Close(conn, NULL, reason, true);
else
Client_Destroy(c, NULL, reason, false);
}
else
Log(LOG_NOTICE, "Client with nick \"%s\" is unknown here.",
Req->argv[0]);
/* Are we still connected or were we killed, too? */
if (my_conn > NONE && Conn_GetClient(my_conn))
return CONNECTED;
else
return DISCONNECTED;
} /* IRC_KILL */
return IRC_KillClient(Client, prefix, Req->argv[0], reason);
}
/**
* Handler for the IRC "NOTICE" command.
@ -376,6 +324,81 @@ IRC_HELP(CLIENT *Client, REQUEST *Req)
return CONNECTED;
} /* IRC_HELP */
/**
* Kill an client identified by its nick name.
*
* Please note that after killig a client, its CLIENT cond CONNECTION
* structures are invalid. So the caller must make sure on its own not to
* access data of probably killed clients after calling this function!
*
* @param Client The client from which the command leading to the KILL has
* been received, or NULL. The KILL will no be forwarded in this
* direction. Only relevant when From is set, too.
* @param From The client from which the command originated, or NULL for
the local server.
* @param Nick The nick name to kill.
* @param Reason Text to send as reason to the client and other servers.
*/
GLOBAL bool
IRC_KillClient(CLIENT *Client, CLIENT *From, const char *Nick, const char *Reason)
{
const char *msg;
CONN_ID my_conn, conn;
CLIENT *c;
/* Inform other servers */
IRC_WriteStrServersPrefix(From ? Client : NULL,
From ? From : Client_ThisServer(),
"KILL %s :%s", Nick, Reason);
/* Do we know such a client? */
c = Client_Search(Nick);
if (!c) {
LogDebug("Client with nick \"%s\" is unknown here.", Nick);
return CONNECTED;
}
if (Client_Type(c) != CLIENT_USER && Client_Type(c) != CLIENT_GOTNICK) {
/* Target of this KILL is not a regular user, this is
* invalid! So we ignore this case if we received a
* regular KILL from the network and try to kill the
* client/connection anyway (but log an error!) if the
* origin is the local server. */
if (Client != Client_ThisServer()) {
/* Invalid KILL received from remote */
if (Client_Type(c) == CLIENT_SERVER)
msg = ERR_CANTKILLSERVER_MSG;
else
msg = ERR_NOPRIVILEGES_MSG;
return IRC_WriteErrClient(Client, msg, Client_ID(Client));
}
Log(LOG_ERR,
"Got KILL for invalid client type: %d, \"%s\"!",
Client_Type(c), Nick);
}
/* Save ID of this connection */
my_conn = Client_Conn(Client);
/* Kill the client NOW:
* - Close the local connection (if there is one),
* - Destroy the CLIENT structure for remote clients.
* Note: Conn_Close() removes the CLIENT structure as well. */
conn = Client_Conn(c);
if(conn > NONE)
Conn_Close(conn, NULL, Reason, true);
else
Client_Destroy(c, NULL, Reason, false);
/* Are we still connected or were we killed, too? */
if (my_conn > NONE && Conn_GetClient(my_conn))
return CONNECTED;
else
return DISCONNECTED;
}
/**
* Send help for a given topic to the client.
*

View File

@ -1,6 +1,6 @@
/*
* ngIRCd -- The Next Generation IRC Daemon
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
* Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
*
* 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
@ -28,6 +28,9 @@ GLOBAL bool IRC_SQUERY PARAMS((CLIENT *Client, REQUEST *Req));
GLOBAL bool IRC_TRACE PARAMS((CLIENT *Client, REQUEST *Req));
GLOBAL bool IRC_HELP PARAMS((CLIENT *Client, REQUEST *Req));
GLOBAL bool IRC_KillClient PARAMS((CLIENT *Client, CLIENT *From,
const char *Nick, const char *Reason));
#endif
/* -eof- */