From f087c68a99951d12ba91c5f6e1e0e548c5a5d912 Mon Sep 17 00:00:00 2001 From: xor Date: Fri, 10 Jun 2011 21:39:01 +0200 Subject: [PATCH] New option to scrub incoming CTCP commands 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 | 6 ++++++ src/ngircd/conf.h | 3 +++ src/ngircd/parse.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index 9e3fe13d..6bd224f3 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -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); diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 80d18187..1f9bd122 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -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; diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index c2603918..72e34309 100644 --- a/src/ngircd/parse.c +++ b/src/ngircd/parse.c @@ -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- */ -- 2.40.0