New option to scrub incoming CTCP commands
authorxor <xorboy@gmail.com>
Fri, 10 Jun 2011 19:39:01 +0000 (21:39 +0200)
committerAlexander Barton <alex@barton.de>
Sat, 25 Jun 2011 19:37:17 +0000 (21:37 +0200)
This patch makes it possible to scrub incomming CTCP commands from
other servers and clients alike. The ngircd oper can enable it from
the config file, by adding "ScrubCTCP = yes" under [OPTIONS]. It is
default off.

CTCP can be used to profile IRC users (get user clients name and
version, and also their IP addresses). This is not something we like
to happen when user pseudonymity/secrecy is important.

The server silently drops incomming CTCP requests from both other
servers and from users. The server that scrubs CTCP will not forward
the CTCP requests to other servers in the network either, which can
spell trouble if not every oper knows about the CTCP-scrubbing.
Scrubbing CTCP commands also means that it is not possible to send
files between users.

There is one exception to the CTCP scrubbing performed: ACTION ("/me
commands") requests are not scrubbed. ACTION is not dangerous to users
(unless they use OTR, which does not encrypt CTCP requests) and most
users would be confused if they were just dropped.

A CTCP request looks like this:

ctcp_char, COMMAND, arg0, arg1, arg2, .. argN, ctcp_char

ctcp_char is 0x01. (just like bold is 0x02 and color is 0x03.)

They are sent as part of a message and can be delivered to channels
and users alike.

src/ngircd/conf.c
src/ngircd/conf.h
src/ngircd/parse.c

index 9e3fe13d0250e682e324fb97851f6cb1031ee12c..6bd224f3c11ea58189d081beb361d97783bf721f 100644 (file)
@@ -374,6 +374,7 @@ Conf_Test( void )
 #ifndef STRICT_RFC
        printf("  RequireAuthPing = %s\n", yesno_to_str(Conf_AuthPing));
 #endif
+       printf("  ScrubCTCP = %s\n", yesno_to_str(Conf_ScrubCTCP));
 #ifdef SSL_SUPPORT
        printf("  SSLCertFile = %s\n", Conf_SSLOptions.CertFile);
        printf("  SSLDHFile = %s\n", Conf_SSLOptions.DHFile);
@@ -687,6 +688,7 @@ Set_Defaults(bool InitServers)
 #endif
        Conf_PredefChannelsOnly = false;
 #ifdef SYSLOG
+       Conf_ScrubCTCP = false;
 #ifdef LOG_LOCAL5
        Conf_SyslogFacility = LOG_LOCAL5;
 #else
@@ -1459,6 +1461,10 @@ Handle_OPTIONS(int Line, char *Var, char *Arg)
                return;
        }
 #endif
+       if (strcasecmp(Var, "ScrubCTCP") == 0) {
+               Conf_ScrubCTCP = Check_ArgIsTrue(Arg);
+               return;
+       }
 #ifdef SSL_SUPPORT
        if (strcasecmp(Var, "SSLCertFile") == 0) {
                assert(Conf_SSLOptions.CertFile == NULL);
index 80d18187db9c16932fb78a6df59c735d244e1195..1f9bd122d02faf311e64bcce5d527163147d8fe3 100644 (file)
@@ -178,6 +178,9 @@ GLOBAL bool Conf_Ident;
 /** Enable all usage of PAM, even when compiled with support for it */
 GLOBAL bool Conf_PAM;
 
+/** Disable all CTCP commands except for /me ? */
+GLOBAL bool Conf_ScrubCTCP;
+
 /** Enable NOTICE AUTH messages on connect */
 GLOBAL bool Conf_NoticeAuth;
 
index c2603918ff430643d045d8e5d95bdfcca43eec8f..72e3430998b301d4011b9b55175e1a91d41875a6 100644 (file)
@@ -47,6 +47,7 @@
 #include "numeric.h"
 
 #include "exp.h"
+#include "conf.h"
 
 struct _NUMERIC {
        int numeric;
@@ -124,6 +125,8 @@ static bool Validate_Args PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
 
 static bool Handle_Request PARAMS(( CONN_ID Idx, REQUEST *Req ));
 
+static bool ScrubCTCP PARAMS((char *Request));
+
 /**
  * Return the pointer to the global "IRC command structure".
  * This structure, an array of type "COMMAND" describes all the IRC commands
@@ -174,8 +177,10 @@ Parse_Request( CONN_ID Idx, char *Request )
        /* remove leading & trailing whitespace */
        ngt_TrimStr( Request );
 
-       if( Request[0] == ':' )
-       {
+       if (Conf_ScrubCTCP && ScrubCTCP(Request))
+               return true;
+
+       if (Request[0] == ':') {
                /* Prefix */
                req.prefix = Request + 1;
                ptr = strchr( Request, ' ' );
@@ -459,7 +464,6 @@ Handle_Numeric(CLIENT *client, REQUEST *Req)
        return IRC_WriteStrClientPrefix(target, prefix, "%s", str);
 }
 
-
 static bool
 Handle_Request( CONN_ID Idx, REQUEST *Req )
 {
@@ -525,4 +529,39 @@ Handle_Request( CONN_ID Idx, REQUEST *Req )
 } /* Handle_Request */
 
 
+/**
+ * Check if incoming messages contains CTCP commands and should be dropped.
+ *
+ * @param Request NULL terminated incoming command.
+ * @returns true, when the message should be dropped.
+ */
+static bool
+ScrubCTCP(char *Request)
+{
+       static const char me_cmd[] = "ACTION ";
+       static const char ctcp_char = 0x1;
+       bool dropCommand = false;
+       char *ptr = Request;
+       char *ptrEnd = strchr(Request, '\0');
+
+       if (Request[0] == ':' && ptrEnd > ptr)
+               ptr++;
+
+       while (ptr != ptrEnd && *ptr != ':')
+               ptr++;
+
+       if ((ptrEnd - ptr) > 1) {
+               ptr++;
+               if (*ptr == ctcp_char) {
+                       dropCommand = true;
+                       ptr++;
+                       /* allow /me commands */
+                       if ((size_t)(ptrEnd - ptr) >= strlen(me_cmd)
+                           && !strncmp(ptr, me_cmd, strlen(me_cmd)))
+                               dropCommand = false;
+               }
+       }
+       return dropCommand;
+}
+
 /* -eof- */