]> arthur.barton.de Git - ngircd-alex.git/commitdiff
Enable SQUIT command for IRC Operators
authorAlexander Barton <alex@barton.de>
Tue, 19 May 2009 20:41:45 +0000 (22:41 +0200)
committerAlexander Barton <alex@barton.de>
Wed, 30 Sep 2009 14:00:06 +0000 (16:00 +0200)
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
src/ngircd/parse.c

index b75a34f9834abf6267d5ebb60faae753cff51a17..ca2502dc62414008abdd558a715d458436aa8b2c 100644 (file)
@@ -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- */
index 6d53525b6f2754875eae94a9baa565800156ac0a..2c28a309a0bebf39076b06450a98ac0d5fdc1265 100644 (file)
@@ -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 },