commit 294320ed62bdb7dac546cea43fac3b4c916788a4 from: Alexander Barton date: Wed Sep 30 14:00:06 2009 UTC 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! commit - 03b70229eb95e218f56ab22ce30fa6279b3ae91f commit + 294320ed62bdb7dac546cea43fac3b4c916788a4 blob - b75a34f9834abf6267d5ebb60faae753cff51a17 blob + ca2502dc62414008abdd558a715d458436aa8b2c --- src/ngircd/irc-server.c +++ 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)); + con = Client_Conn(target); - 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); + 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- */ blob - 6d53525b6f2754875eae94a9baa565800156ac0a blob + 2c28a309a0bebf39076b06450a98ac0d5fdc1265 --- src/ngircd/parse.c +++ 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 },