From b5faf3055b61afaef73ac49a448cac1a5b063127 Mon Sep 17 00:00:00 2001 From: Alexander Barton Date: Tue, 1 Oct 2013 12:13:17 +0200 Subject: [PATCH] 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! --- src/ngircd/irc-login.c | 66 +++++++------------- src/ngircd/irc.c | 135 ++++++++++++++++++++++++----------------- src/ngircd/irc.h | 5 +- 3 files changed, 105 insertions(+), 101 deletions(-) diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index 013481d2..af087f9d 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -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. * diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 34180aa7..74b8a018 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -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. * diff --git a/src/ngircd/irc.h b/src/ngircd/irc.h index c2f9b662..03fb0dc4 100644 --- a/src/ngircd/irc.h +++ b/src/ngircd/irc.h @@ -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- */ -- 2.39.2