From 294320ed62bdb7dac546cea43fac3b4c916788a4 Mon Sep 17 00:00:00 2001 From: Alexander Barton Date: Tue, 19 May 2009 22:41:45 +0200 Subject: [PATCH] Enable SQUIT command for IRC Operators This patch enables IRC Operators to use the SQUIT command as specified in RFC 2812, section 3.1.8 "Squit". When forwarding SQUIT commands, the server connected to the target will drop the connection (not the target server itself!). Please note: - the configuration option "AllowRemoteOper" mus be enabled on the server disconnecting the target to allow forwarding of SQUIT commands. - if the remote server is configured to establish the connection, it will just do this; so the disconnect is not permanent in this case! --- src/ngircd/irc-server.c | 81 ++++++++++++++++++++++++++++++----------- src/ngircd/parse.c | 2 +- 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/src/ngircd/irc-server.c b/src/ngircd/irc-server.c index b75a34f9..ca2502dc 100644 --- a/src/ngircd/irc-server.c +++ b/src/ngircd/irc-server.c @@ -37,6 +37,7 @@ #include "numeric.h" #include "ngircd.h" #include "irc-info.h" +#include "op.h" #include "exp.h" #include "irc-server.h" @@ -273,21 +274,40 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req ) GLOBAL bool IRC_SQUIT(CLIENT * Client, REQUEST * Req) { - CLIENT *target; - char msg[LINE_LEN + 64]; + char msg[COMMAND_LEN], logmsg[COMMAND_LEN]; + CLIENT *from, *target; + CONN_ID con; assert(Client != NULL); assert(Req != NULL); + if (Client_Type(Client) != CLIENT_SERVER + && !Client_HasMode(Client, 'o')) + return Op_NoPrivileges(Client, Req); + /* Bad number of arguments? */ if (Req->argc != 2) return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); + if (Client_Type(Client) == CLIENT_SERVER && Req->prefix) { + from = Client_Search(Req->prefix); + if (Client_Type(from) != CLIENT_SERVER + && !Op_Check(Client, Req)) + return Op_NoPrivileges(Client, Req); + } else + from = Client; + if (!from) + return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, + Client_ID(Client), Req->prefix); + Log(LOG_DEBUG, "Got SQUIT from %s for \"%s\": \"%s\" ...", - Client_ID(Client), Req->argv[0], Req->argv[1]); + Client_ID(from), Req->argv[0], Req->argv[1]); target = Client_Search(Req->argv[0]); + if (Client_Type(Client) != CLIENT_SERVER && + target == Client_ThisServer()) + return Op_NoPrivileges(Client, Req); if (!target) { /* The server is (already) unknown */ Log(LOG_WARNING, @@ -296,27 +316,46 @@ IRC_SQUIT(CLIENT * Client, REQUEST * Req) return CONNECTED; } - if (Req->argv[1][0]) { - if (strlen(Req->argv[1]) > LINE_LEN) - Req->argv[1][LINE_LEN] = '\0'; - snprintf(msg, sizeof(msg), "%s (SQUIT from %s).", Req->argv[1], - Client_ID(Client)); - } else - snprintf(msg, sizeof(msg), "Got SQUIT from %s.", - Client_ID(Client)); - - if (Client_Conn(target) > NONE) { - /* We are directly connected to this server */ - if (Req->argv[1][0]) - Conn_Close(Client_Conn(target), msg, Req->argv[1], - true); + con = Client_Conn(target); + + if (Req->argv[1][0]) + if (Client_NextHop(from) != Client || con > NONE) + snprintf(msg, sizeof(msg), "%s (SQUIT from %s)", + Req->argv[1], Client_ID(from)); else - Conn_Close(Client_Conn(target), msg, NULL, true); - return DISCONNECTED; + strlcpy(msg, Req->argv[1], sizeof(msg)); + else + snprintf(msg, sizeof(msg), "Got SQUIT from %s", + Client_ID(from)); + + if (con > NONE) { + /* We are directly connected to the target server, so we + * have to tear down the connection and to inform all the + * other remaining servers in the network */ + Conn_Close(con, NULL, msg, true); + if (con == Client_Conn(Client)) + return DISCONNECTED; } else { - Client_Destroy(target, msg, Req->argv[1], false); - return CONNECTED; + /* This server is not directly connected, so the SQUIT must + * be forwarded ... */ + if (Client_Type(from) != CLIENT_SERVER) { + /* The origin is not an IRC server, so don't evaluate + * this SQUIT but simply forward it */ + IRC_WriteStrClientPrefix(Client_NextHop(target), + from, "SQUIT %s :%s", Req->argv[0], Req->argv[1]); + } else { + /* SQUIT has been generated by another server, so + * remove the target server from the network! */ + logmsg[0] = '\0'; + if (!strchr(msg, '(')) + snprintf(logmsg, sizeof(logmsg), + "%s (SQUIT from %s)", Req->argv[1], + Client_ID(from)); + Client_Destroy(target, logmsg[0] ? logmsg : msg, + msg, false); + } } + return CONNECTED; } /* IRC_SQUIT */ /* -eof- */ diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index 6d53525b..2c28a309 100644 --- a/src/ngircd/parse.c +++ b/src/ngircd/parse.c @@ -92,7 +92,7 @@ static COMMAND My_Commands[] = { "SERVICE", IRC_SERVICE, 0xFFFF, 0, 0, 0 }, { "SERVLIST", IRC_SERVLIST, CLIENT_USER, 0, 0, 0 }, { "SQUERY", IRC_SQUERY, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, - { "SQUIT", IRC_SQUIT, CLIENT_SERVER, 0, 0, 0 }, + { "SQUIT", IRC_SQUIT, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "STATS", IRC_STATS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "SUMMON", IRC_SUMMON, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "TIME", IRC_TIME, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, -- 2.39.2