commit b5faf3055b61afaef73ac49a448cac1a5b063127 from: Alexander Barton date: Tue Oct 01 10:13:17 2013 UTC 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! commit - cccd8fc957e893e250324b65146df8fca4680f11 commit + b5faf3055b61afaef73ac49a448cac1a5b063127 blob - 013481d2275029b664019126a6926d3e978dc222 blob + af087f9dcdd7d01907e749745e0111896aa46a7a --- src/ngircd/irc-login.c +++ 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); @@ -856,31 +859,6 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) } /* 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. * * @param Origin The client which caused the nickname change. blob - 34180aa7d48eb04130da17ffdd712909859204bf blob + 74b8a018cf1a5d8dc3da0541964748f186928562 --- src/ngircd/irc.c +++ 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,60 +165,9 @@ 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] ); - } + return IRC_KillClient(Client, prefix, Req->argv[0], reason); +} - /* 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 */ - /** * Handler for the IRC "NOTICE" command. * @@ -377,6 +325,81 @@ IRC_HELP(CLIENT *Client, REQUEST *Req) } /* 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. * * @param Client The client requesting help. blob - c2f9b66244eba0c3fc84db90f1104cd60b4d3758 blob + 03fb0dc45bbe1e02893a8ab4d0ccf1950003b54d --- src/ngircd/irc.h +++ 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 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- */