#include "module.h" #define AUTHOR "SGR" #define VERSION "2.98" /* ----------------------------------------------------------- * Name : ircd_ctcpserv * Author: SGR * Date : 17/11/2003 * ----------------------------------------------------------- * Functions: my_privmsgA, my_nickA, ctcp_check, * timeout_version_user, CheckOffDefList, * CheckCustomDefList * Limitations: Anope1.5.6-r30 and later only. * Tested: Ultimate(2.8.x), Unreal(3.2), Viagra, Ultimate(3.x) * ----------------------------------------------------------- * This version has been tested on Ultimate, Viagra and * Unreal. * * This modules has 15 configurable options * * Please read the comments by each one. * * Some future version should have JOIN "/msg CTCPServ VALID" * option - that would allow clients to report that they are * real if they match a 'defintion' - thus preventing 'action'. * * Version Changes: * * 1: Core, many segfaults, in-code only def checking. * 2: Core, All segfaults cleared. * 3: Reading from files, kill or akill option added. * 4: Bugs from above code ignored, alog and globops added * 5: Reading from def files added, structure not used due * to possible memory limits. * 6: Help and in-IRC SET command added. All reported bugs * cleared. Sorted some memory allocation issues that * caused random segfaults and tested all detection * and action systems. * 7: Fixed some typos in the messages responses from the * SET command, added Version change log. * 8: Fixed a problem in it not detecting any dodgy clients * as I had ignored CTCP protocall. * 9: Removed unnecessary Akill checking. Fixed "less than * 1 char from def" bug. * 10: have done full scale testing. thanks VERY much to the * staff of irc.weaklinks.net (a great network i must say) * I hope the 500+ akills on bottler clients we set in * one hour help keep your servers a little less laggy ;) * 11: Fixed some screw-ups due to Ultimates protocall * implementation, updated logging system * 12: Sorted out an issue where /Nick'ing users were sometimes * ignored and no user struct created for them. * 13: Added optional 'Check ID'd and Opered users' setting. * 14: Added Optional NOTICE parameter. * Thanks especially to Rob - for discovering the * ultimate client connect annouce is 'wank' :) * 15: Resoved 'on nick change, invalid argc' error. * 16: Found and fixed an error where def files were not * closed, ultimatly causing a user to hit the file * descriptor limit for a process. * 17: Added option for default check and logging settings * at the bottom of configuration block, and updated * on load log-chan info to boot. * 18: Fixed practically unnoticable memory leak reported * by Certus :) * 19: Added "rejoin on kill" system. * 20: Added QUIT message to rejoin on kill system, should * prevent crap IRCd's getting stuck in a loop attempting * to kill CTCPServ on re-introduction. * 21: Added an option to kill if clients don't reply. * 22: Added Anope-1.7.x SVN (revision 370+) support. * * Thanks to dengel, Rob and Certus for all there support. * Thanks to "raw" (mario@*.ipt.aol.com) and 'Larry' for * there excellent help in providing bug reports and * backtraces. * ----------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /* START OF CONFIGURATION BLOCK - please read the comments :) */ /* ---------------------------------------------------------------------- */ /* If you are using Anope-1.7.x or later, leave this alone. * Otherwise change it to '#undef ANOPE17x' (no quotes). * * THIS IS IMPORTANT * */ #define ANOPE17x /* NONE OF THE BELOW MESSAGES SHOULD BE LONGER THAN 450 characters - * including spaces. */ /* The below is noticed to users before they are KILLED or AKILLED. * comment out or modify as necessary. Not all 6 need be used. */ #define cNOTICE1 "You appear to be using a trojan, very outdated or forbidden client." #define cNOTICE2 "For more information on this, and how to fix it, please refer to" #define cNOTICE3 "this website: /dev/null" #define cNOTICE4 "You shall now be removed from the network, we appologise for any" #define cNOTICE5 "inconvienience caused." /* #define cNOTICE6 "bleh blah bleh blah" */ /* The below is noticed to users when ACTION is set to NOTICE. * comment out or modify as necessary. Not all 10 need be used. */ #define ccNOTICE1 "You appear to be using a trojan or very outdated client." #define ccNOTICE2 "For more information on this, and how to fix it, please refer to " #define ccNOTICE3 "this website: /dev/null. or join #Help." //#define ccNOTICE4 " " //#define ccNOTICE5 " " //#define ccNOTICE6 " " //#define ccNOTICE7 " " //#define ccNOTICE8 " " //#define ccNOTICE9 " " //#define ccNOTICE10 " " /**************************************** FOR THE BELOW SETTINGS **ONLY** * CHANGE WHAT IS **INSIDE** THE * "Speach marks". ****************************************/ /* If this is defined, TIME_TO_WAIT_BEFORE_CTCP will NOT be used and * clients will be versioned instantly on connecting. */ #define CTCP_INSTANTLY /* ACTION_NO_REPLY_USERS -- If this is defined, CTCPServ will take * action on clients that DO NOT reply to the CTCP request within * NO_REPLY_TIMEOUT. This setting is not recommended :). * * The action performed will the the same as the one set for * users who reply with a matched defintion. */ #define ACTION_NO_REPLY_USERS #define NO_REPLY_TIMEOUT "30s" /* Time to wait before CTCPing users who have joined the network - MANDATORY * Note that an integer followed by a letter == the time. * e.g: 3s = 3 seconds; 3m = 3 mins; 3h = 3 hours; 3d = 3 days. * set to a sensible time, e.g 3s to 30s [NOT less than 1s] */ #define TIME_TO_WAIT_BEFORE_CTCP 3s /* The reason with which clients are killed - MANDATORY */ #define KILL_REASON "You appear to be using a trojan, very outdated or forbidden client."; /* The reason with which clients are Akilled - MANDATORY */ #define AKILL_REASON "You appear to be using a trojan, very outdated or forbidden client."; /* The below setting determins what action should be taken on the clients whose * replies match a definition. There are currenly 5 settings: * 0: Kill matches * 1: AKILL matches * 2: Globops (Send a message to all global IRCops) * 3: Send to LogChan Only. * 4: Notice the user. * * This setting is MANDATORY */ #define DEFAULT_ACTION 0 /* This is used if KillClonesAkillExpire is not set in the services.conf * or if DONT_USE_KILL_CLONES_TIME is defined below. Please note this is * subject to ExpireTimeout. * * This value _CANNOT_ be larger than 2147483647 (about 68 years) * This value _MUST_ larger than 60 - MANDATORY * * NB: its recommended this is not set more than a few days as when a * large botnet joins the network, the AKILL list can fill up quickly. * My personal recommendation is about 3 hours. * */ #define AKILL_TIME_IN_SECONDS 10800 /* 3 hours */ /* Set to 1 to force the above time to be used. * (and NOT the KillClonesAkillExpire from the services.conf file) */ #define DONT_USE_KILL_CLONES_TIME 1 /* On load status - should I automatically start checking clients? * SET CHECK [ALL | ON | OFF ] * 2 1 0 * Diff between ON and ALL - when ON only clients who don't ID to * NickServ or /Oper up in TIME_TO_WAIT_BEFORE_CTCP will be checked * * This setting MUST be 0, 1 or 2 */ #define DEFAULT_MODE 1 /* on load logging status * SET LOGGING [OFF|BASIC|USEFUL|VERBOSE|FULL]" * 0 1 2 3 4 * 0 - Off * 1 - Every Action * 2 - Every Match + Every Action + Every FAIL * 3 - Every New User Versioned + Every Match + Every Action * 4 - Detected User + Every New User Versioned + Every Match + Every Action * * This setting MUST be 0, 1, 2, 3 or 4 */ #define DEFAULT_LOG_LEVEL 1 /* ---------------------------------------------------------------------- */ /* DO NOT EDIT BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING */ /* ---------------------------------------------------------------------- */ /* Set these to be the Nick, Host and Realname of the CTCPServ Psudo * client, as per your whims. */ /* Nickname - NICKLEN character MAXIMUM - (see your IRCd's protocall response for this) */ char *s_CTCPServ = "CTCPServ"; /* HostMask: 64 character MAXIMUM */ char *s_CTCPServHOST = "CTCPServ.Network.Protection.Bot"; /* Realname 30 character MAXIMUM */ char *s_CTCPServREALNAME = "CTCP Responce Checker"; int timeout_kill_user(int argc, char **argv); int my_privmsgA(char *source, int ac, char **av); int my_nickA(char *source, int ac, char **av); int ctcp_check(User * u, char *buf); int timeout_version_user(int argc, char **argv); int CheckOffDefList(char *to_be_matched_off); int kill_due_to_version(User *u); int CheckCustomDefList(char *to_be_matched); int my_ctcpserv_killrejoin(char *source, int ac, char **av); int cTAKEACTION = DEFAULT_ACTION; int cAKILLTIMEINSECONDS = AKILL_TIME_IN_SECONDS; int cDONTUSEKILLCONESTIME = DONT_USE_KILL_CLONES_TIME; int cDEFAULTMODE = DEFAULT_MODE; int cDEFAULTLOGLEVEL = DEFAULT_LOG_LEVEL; char *cAKILLREASON = AKILL_REASON; char *cKILLREASON = KILL_REASON; int CTCPid = 0; int donotchecktrue = 0; int CTCPServLOGLEV = 0; #ifdef ANOPE17x #define NEWNICK(a,b,c,d,e,f) anope_cmd_bot_nick(a,b,c,d,ircd->botserv_bot_mode) #define wallops anope_cmd_global #endif #ifdef ACTION_NO_REPLY_USERS typedef struct CTCPU_ CTCPU; struct CTCPU_ { CTCPU *next; CTCPU *prev; char *nick; time_t time; }; #define HASH_SIZE 8192 CTCPU *ctcpuhash[HASH_SIZE]; unsigned int ctcpunum = 0; static void add_entry(CTCPU *fc); static int del_entry(CTCPU *fc); static CTCPU *create_entry(char *nick); static CTCPU *find_ctcpu_entry(char *nick); #endif int AnopeInit(int argc, char **argv) { Message *msg = NULL; int status; msg = createMessage("PRIVMSG", my_privmsgA); status = moduleAddMessage(msg, MOD_HEAD); msg = createMessage("NOTICE", my_privmsgA); status = moduleAddMessage(msg, MOD_HEAD); #if defined(IRC_ULTIMATE3) msg = createMessage("CLIENT", my_nickA); #else msg = createMessage("NICK", my_nickA); #endif status = moduleAddMessage(msg, MOD_TAIL); msg = createMessage("KILL", my_ctcpserv_killrejoin); status = moduleAddMessage(msg, MOD_HEAD); if (status == MOD_ERR_OK) { kill_user(NULL, s_CTCPServ, "This nick is now being used by Services"); // Lets just make sure. NEWNICK(s_CTCPServ, s_CTCPServ, s_CTCPServHOST, s_CTCPServREALNAME, "+ioS", 1); } moduleAddAuthor(AUTHOR); moduleAddVersion(VERSION); donotchecktrue = cDEFAULTMODE; CTCPServLOGLEV = cDEFAULTLOGLEVEL; alog("[ircd_ctcpserv] This module has loaded and is now active."); alog("[ircd_ctcpserv] For information see /msg %s HELP", s_CTCPServ); if (!cDEFAULTMODE) { alog("[ircd_ctcpserv] %s Protection DISABLED. To activate protection now, use: /msg %s SET CHECK ON", s_CTCPServ, s_CTCPServ); } if (cDEFAULTMODE) { if (cDEFAULTMODE > 1) { alog("[ircd_ctcpserv] %s - Protection activated for ALL clients.", s_CTCPServ); } if (cDEFAULTMODE == 1) { alog("[ircd_ctcpserv] %s - Protection activated.", s_CTCPServ); } } if (!cDEFAULTLOGLEVEL) { alog("[ircd_ctcpserv] %s - Logging set to OFF. Use: /msg %s SET LOGGING ON - to enable.", s_CTCPServ, s_CTCPServ); } if (cDEFAULTLOGLEVEL == 1) { alog("[ircd_ctcpserv] %s - Logging set to BASIC.", s_CTCPServ); } if (cDEFAULTLOGLEVEL == 2) { alog("[ircd_ctcpserv] %s - Logging set to USEFUL.", s_CTCPServ); } if (cDEFAULTLOGLEVEL == 3) { alog("[ircd_ctcpserv] %s - Logging set to VERBOSE.", s_CTCPServ); } if (cDEFAULTLOGLEVEL == 4) { alog("[ircd_ctcpserv] %s - Logging set to FULL.", s_CTCPServ); } return MOD_CONT; } void AnopeFini(void) { send_cmd(s_CTCPServ, "QUIT :Module Unloaded!"); } int my_privmsgA(char *source, int ac, char **msg) { /* an uglier version of Rob's CatServ module code */ User *u; char *s; /* First, some basic checks */ if (ac != 2) { /* bleh */ return MOD_CONT; } if (!(u = finduser(source))) { return MOD_CONT; } /* non-user source */ if (*msg[0] == '#') { return MOD_CONT; } /* Channel message */ s = strchr(msg[0], '@'); if (s) { *s++ = 0; if (stricmp(s, ServerName) != 0) { return MOD_CONT; } } if ((stricmp(msg[0], s_CTCPServ)) == 0) { /* its for US! */ ctcp_check(u, msg[1]); return MOD_STOP; } else { /* ok it isnt us, let the old code have it */ return MOD_CONT; } } /*****************************************************************************/ int ctcp_check(User * u, char *buf) { char *isversion = strtok(buf, " "); char *s; char *t; if (!isversion) { return MOD_STOP; } if (stricmp(isversion, "\1PING") == 0) { if (!(s = strtok(NULL, ""))) { s = "\1"; } notice(s_CTCPServ, u->nick, "\1PING %s", s); return MOD_STOP; } if (skeleton) { notice_lang(s_CTCPServ, u, SERVICE_OFFLINE, s_CTCPServ); return MOD_STOP; } if (CTCPServLOGLEV > 3) { alog("[ircd_ctcpversion] - Got a message - starts: %s", isversion); } if (stricmp(isversion, "\1VERSION") == 0) { #ifdef ACTION_NO_REPLY_USERS CTCPU *moo; #endif if (CTCPServLOGLEV > 3) { alog("[ircd_ctcpversion] - Its a VERSION!"); } #ifdef ACTION_NO_REPLY_USERS if ((moo = find_ctcpu_entry(u->nick))) { del_entry(moo); } #endif if (donotchecktrue) { if (!(s = strtok(NULL, ""))) { s = "\1"; } if (CTCPServLOGLEV > 3) { alog("[ircd_ctcpversion] - Checking | %s | against def lists.", s); } if (CheckCustomDefList(s) == 1) { kill_due_to_version(u); return MOD_STOP; } if (CheckOffDefList(s) == 1) { kill_due_to_version(u); return MOD_STOP; } } } if (stricmp(isversion, "HELP") == 0) { s = strtok(NULL, " "); if (!s) { notice(s_CTCPServ, u->nick, "-----------------------------------------------------------------------"); notice(s_CTCPServ, u->nick, "%s checks users CTCP versions as they join the network.", s_CTCPServ); notice(s_CTCPServ, u->nick, "This is done so we can quickly remove mass-spam or clone bots."); notice(s_CTCPServ, u->nick, "If you match a forbidden client you may be forcefully removed"); notice(s_CTCPServ, u->nick, "from the network. For more information join the official help"); notice(s_CTCPServ, u->nick, "room."); if (is_oper(u)) { notice(s_CTCPServ, u->nick, " "); notice(s_CTCPServ, u->nick, "The module version is %s", VERSION); notice(s_CTCPServ, u->nick, " "); notice(s_CTCPServ, u->nick, "New defintions should be added to custom.dat"); notice(s_CTCPServ, u->nick, "Please remember to NOT modify the official.dat file - "); notice(s_CTCPServ, u->nick, "and to only add your own 'definitions' to the custom.dat"); notice(s_CTCPServ, u->nick, "file; offical.dat may get updated, check the anope forums."); notice(s_CTCPServ, u->nick, "This file [custom.dat] can be updated \"on the fly\" so no"); notice(s_CTCPServ, u->nick, "'reshashing' is needed. Please ensure there are NO blank lines."); notice(s_CTCPServ, u->nick, "in this file."); notice(s_CTCPServ, u->nick, " "); notice(s_CTCPServ, u->nick, "For help on setting %s options see /msg %s HELP SET", s_CTCPServ, s_CTCPServ); } notice(s_CTCPServ, u->nick, "-----------------------------------------------------------------------"); return MOD_CONT; } if (is_services_admin(u)) { if (stricmp(s, "NOTICES") == 0) { notice(s_CTCPServ, u->nick, "-----------------------------------------------------------------------"); notice(s_CTCPServ, u->nick, "These notices will be noticed to uses when NOTIFY is set as the"); notice(s_CTCPServ, u->nick, "%s action when checking is on.", s_CTCPServ); notice(s_CTCPServ, u->nick, "-----------------------------------------------------------------------"); #ifdef ccNOTICE1 notice(s_CTCPServ, u->nick, ccNOTICE1); #endif #ifdef ccNOTICE2 notice(s_CTCPServ, u->nick, ccNOTICE2); #endif #ifdef ccNOTICE3 notice(s_CTCPServ, u->nick, ccNOTICE3); #endif #ifdef ccNOTICE4 notice(s_CTCPServ, u->nick, ccNOTICE4); #endif #ifdef ccNOTICE5 notice(s_CTCPServ, u->nick, ccNOTICE5); #endif #ifdef ccNOTICE6 notice(s_CTCPServ, u->nick, ccNOTICE6); #endif #ifdef ccNOTICE7 notice(s_CTCPServ, u->nick, ccNOTICE7); #endif #ifdef ccNOTICE8 notice(s_CTCPServ, u->nick, ccNOTICE8); #endif #ifdef ccNOTICE9 notice(s_CTCPServ, u->nick, ccNOTICE9); #endif #ifdef ccNOTICE10 notice(s_CTCPServ, u->nick, ccNOTICE10); #endif notice(s_CTCPServ, u->nick, "-----------------------------------------------------------------------"); return MOD_CONT; } if (stricmp(s, "SET") == 0) { notice(s_CTCPServ, u->nick, "-----------------------------------------------------------------------"); notice(s_CTCPServ, u->nick, "Syntax: SET ACTION [KILL|AKILL|GLOBOPS|ALOG|NOTICE]"); notice(s_CTCPServ, u->nick, "Syntax: SET CHECK [ALL|ON|OFF]"); notice(s_CTCPServ, u->nick, "Syntax: SET LOGGING [OFF|BASIC|USEFUL|VERBOSE|FULL]"); notice(s_CTCPServ, u->nick, " "); notice(s_CTCPServ, u->nick, "SET ACTION: Set the action that is peformed on detected clients, ALOG"); notice(s_CTCPServ, u->nick, " will force a LogChan message. NOTICE will cause the notices"); notice(s_CTCPServ, u->nick, " listed in /msg %s HELP NOTICES be broadcast to detected", s_CTCPServ); notice(s_CTCPServ, u->nick, " users. The rest should be self-explainatory. "); notice(s_CTCPServ, u->nick, " "); notice(s_CTCPServ, u->nick, "SET CHECK: Set if the CTCP VERSION on connect is actually used. This"); notice(s_CTCPServ, u->nick, " command is designed to stop the checks for a short time"); notice(s_CTCPServ, u->nick, " without a SRA having to unload the module. ALL means that"); notice(s_CTCPServ, u->nick, " ALL clients will be checked, ON means only non-ID'd and"); notice(s_CTCPServ, u->nick, " non-opered client will be checked (after timeout) and OFF"); notice(s_CTCPServ, u->nick, " means no clients will be checked at all."); notice(s_CTCPServ, u->nick, " "); notice(s_CTCPServ, u->nick, "SET LOGGING: This command sets how verbose %s's logging is. When set to", s_CTCPServ); notice(s_CTCPServ, u->nick, " OFF, there is no logging what-so-ever. When set to BASIC, logs"); notice(s_CTCPServ, u->nick, " of clients who ilicit ACTION are made to the logchan."); notice(s_CTCPServ, u->nick, " When set to USEFUL, CTCPServ will send logchan messages of"); notice(s_CTCPServ, u->nick, " the definition matched and the action ensuing it. VERBOSE"); notice(s_CTCPServ, u->nick, " puts all relevant info into the logchan, and finally FULL"); notice(s_CTCPServ, u->nick, " is used for debugging purposes. "); notice(s_CTCPServ, u->nick, " "); notice(s_CTCPServ, u->nick, "NOTE: If this module is unloaded these settings are lost."); notice(s_CTCPServ, u->nick, "-----------------------------------------------------------------------"); return MOD_CONT; } } return MOD_CONT; } if (stricmp(isversion, "SET") == 0) { if (!is_services_admin(u)) { return MOD_CONT; } s = strtok(NULL, " "); t = strtok(NULL, " "); if (!s || !t) { notice(s_CTCPServ, u->nick, "See \2/msg %s HELP SET\2 for more information.", s_CTCPServ); return MOD_CONT; } if (stricmp(s, "ACTION") == 0) { if (stricmp(t, "KILL") == 0) { cTAKEACTION = 0; notice(s_CTCPServ, u->nick, "Action sucessfully set to KILL"); wallops(s_CTCPServ, "%s set %s action to KILL", u->nick, s_CTCPServ); return MOD_CONT; } if (stricmp(t, "AKILL") == 0) { cTAKEACTION = 1; notice(s_CTCPServ, u->nick, "Action sucessfully set to AKILL"); wallops(s_CTCPServ, "%s set %s action to AKILL", u->nick, s_CTCPServ); return MOD_CONT; } if (stricmp(t, "GLOBOPS") == 0) { cTAKEACTION = 2; notice(s_CTCPServ, u->nick, "Action sucessfully set to GLOBOPS"); wallops(s_CTCPServ, "%s set %s action to GLOBOPS", u->nick, s_CTCPServ); return MOD_CONT; } if (stricmp(t, "ALOG") == 0) { cTAKEACTION = 3; notice(s_CTCPServ, u->nick, "Action sucessfully set to ALOG"); wallops(s_CTCPServ, "%s set %s action to ALOG", u->nick, s_CTCPServ); return MOD_CONT; } if (stricmp(t, "NOTICE") == 0) { cTAKEACTION = 4; notice(s_CTCPServ, u->nick, "Action sucessfully set to NOTICE"); wallops(s_CTCPServ, "%s set %s action to NOTICE", u->nick, s_CTCPServ); return MOD_CONT; } else { notice(s_CTCPServ, u->nick, "See \2/msg %s HELP SET\2 for more information.", s_CTCPServ); } return MOD_CONT; } /* ------------ * Checking INT's * ------------ * OFF = 0 * ON = 1 * ALL = 2 * */ if (stricmp(s, "CHECK") == 0) { if (stricmp(t, "OFF") == 0) { donotchecktrue = 0; notice(s_CTCPServ, u->nick, "You sucessfully disabled CTCP VERSION checking."); wallops(s_CTCPServ, "%s set %s on connect CTCP VERSION checking OFF.", u->nick, s_CTCPServ); return MOD_CONT; } if (stricmp(t, "ON") == 0) { donotchecktrue = 1; notice(s_CTCPServ, u->nick, "You sucessfully enabled CTCP VERSION checking."); wallops(s_CTCPServ, "%s set %s on connect CTCP VERSION checking ON.", u->nick, s_CTCPServ); return MOD_CONT; } if (stricmp(t, "ALL") == 0) { donotchecktrue = 2; notice(s_CTCPServ, u->nick, "You sucessfully enabled CTCP VERSION checking [ALL clients]."); wallops(s_CTCPServ, "%s set %s on connect CTCP VERSION checking ON [ALL clients].", u->nick, s_CTCPServ); return MOD_CONT; } else { notice(s_CTCPServ, u->nick, "See \2/msg %s HELP SET\2 for more information.", s_CTCPServ); } return MOD_CONT; } /* ---------- * Logging INT's *----------- * 0 Off * 1 Every Action * 2 Every Match + Every Action + Every FAIL * 3 Every New User Versioned + Every Match + Every Action * 4 Detected User + Every New User Versioned + Every Match + Every Action */ if (stricmp(s, "LOGGING") == 0) { if (stricmp(t, "OFF") == 0) { CTCPServLOGLEV = 0; notice(s_CTCPServ, u->nick, "You sucessfully set %s logging to OFF.", s_CTCPServ); wallops(s_CTCPServ, "%s set sucessfully set %s logging to OFF.", u->nick, s_CTCPServ); return MOD_CONT; } if (stricmp(t, "BASIC") == 0) { CTCPServLOGLEV = 1; notice(s_CTCPServ, u->nick, "You sucessfully set %s logging to BASIC.", s_CTCPServ); wallops(s_CTCPServ, "%s set sucessfully set %s logging to BASIC.", u->nick, s_CTCPServ); return MOD_CONT; } if (stricmp(t, "USEFUL") == 0) { CTCPServLOGLEV = 2; notice(s_CTCPServ, u->nick, "You sucessfully set %s logging to USEFUL.", s_CTCPServ); wallops(s_CTCPServ, "%s set sucessfully set %s logging to USEFUL.", u->nick, s_CTCPServ); return MOD_CONT; } if (stricmp(t, "VERBOSE") == 0) { CTCPServLOGLEV = 3; notice(s_CTCPServ, u->nick, "You sucessfully set %s logging to VERBOSE.", s_CTCPServ); wallops(s_CTCPServ, "%s set sucessfully set %s logging to VERBOSE.", u->nick, s_CTCPServ); return MOD_CONT; } if (stricmp(t, "FULL") == 0) { CTCPServLOGLEV = 4; notice(s_CTCPServ, u->nick, "You sucessfully set %s logging to FULL.", s_CTCPServ); wallops(s_CTCPServ, "%s set sucessfully set %s logging to FULL.", u->nick, s_CTCPServ); return MOD_CONT; } } } return MOD_CONT; } int my_nickA(char *source, int ac, char **av) { #ifndef CTCP_INSTANTLY char CTCPidx[16]; #endif char *argv[1]; if (CTCPServLOGLEV > 3) { alog("[ircd_ctcpversion] - Hooked NICK/CLIENT Message"); } if (ac < 2) { if (CTCPServLOGLEV > 2) { alog("CTCPServ [ircd_ctcpversion] ERROR - NICK/CLIENT MSG LACKS NECESSARY ARGUMENTS"); } return MOD_CONT; } if (CTCPServLOGLEV > 3) { alog("[ircd_ctcpversion] - Found a new user :D"); } #ifndef IRC_ULTIMATE3 if (*source) { return MOD_CONT; } #endif if (CTCPServLOGLEV > 3) { alog("[ircd_ctcpversion] - av0 %s av1 %s av2 %s", av[0], av[1], av[2] ); } argv[0] = sstrdup(av[0]); #ifndef CTCP_INSTANTLY CTCPid = CTCPid + 1; snprintf(CTCPidx, sizeof(CTCPidx), "CTCP-%d", CTCPid); if (moduleAddCallback(CTCPidx, time(NULL)+dotime(TIME_TO_WAIT_BEFORE_CTCP), timeout_version_user,1,argv) != MOD_ERR_OK) { alog("CTCPServ [ircd_ctcpversion] --------- ERROR REPORT -------"); alog("CTCPServ [ircd_ctcpversion] moduleAddCallback Failed. (Timeout setting for function"); alog("CTCPServ [ircd_ctcpversion] int timeout_version_user; args: %s)", av[0]); alog("CTCPServ [ircd_ctcpversion] MOD_ERR_OK not returned. Please report this to the module developer"); alog("CTCPServ [ircd_ctcpversion] ------- ERROR REPORT END------"); free(argv[0]); return MOD_CONT; } if (CTCPid > 2147483600) { CTCPid = 1; } #else timeout_version_user(1, argv); #endif free(argv[0]); return MOD_CONT; } int timeout_version_user(int argc, char **argv) { User *u2; char *peep = argv[0]; if (!argc) { return MOD_STOP; } if (finduser(peep)) { u2 = finduser(peep); if (donotchecktrue < 2 ) { if ((is_oper(u2)) || (nick_identified(u2))) { if (CTCPServLOGLEV > 3) { alog("[ircd_ctcpversion] %s - Not being checked (is an Oper or NickServ Identifed)", u2->nick); } return MOD_CONT; } } if (donotchecktrue) { #ifdef ACTION_NO_REPLY_USERS char CTCPidx[16]; char *argG[1]; #endif if (CTCPServLOGLEV > 2) { alog("[ircd_ctcpversion] Version Checking %s", u2->nick); } send_cmd(s_CTCPServ, "PRIVMSG %s :\1VERSION\1", u2->nick); #ifdef ACTION_NO_REPLY_USERS create_entry(u2->nick); CTCPid = CTCPid + 1; snprintf(CTCPidx, sizeof(CTCPidx), "NICK-%d", CTCPid); if (CTCPid > 2147483600) { CTCPid = 1; } argG[0] = sstrdup(u2->nick); moduleAddCallback(CTCPidx, time(NULL)+dotime(NO_REPLY_TIMEOUT), timeout_kill_user,1,argG); #endif } } else { if (CTCPServLOGLEV > 1) { alog("[ircd_ctcpversion] ERROR - could not find %s [Perhaps they Quit]", peep); } } return MOD_CONT; } int timeout_kill_user(int argc, char **argv) { CTCPU *moo; User *u; if ((moo = find_ctcpu_entry(argv[0]))) { if ((u = finduser(moo->nick))) { kill_due_to_version(u); } del_entry(moo); } return MOD_CONT; } /*-----------------------------------------------*/ int CheckOffDefList(char *to_be_matched) { FILE *OffDef; char definition_string[128]; int len = 0; // Open the file (r == in read only mode) OffDef = fopen("official.dat","r"); // if the file is there, loop until there is no // more data to be read from the file if (OffDef) { while (fgets(definition_string, 127, OffDef) != NULL) { len = strlen(definition_string); // replace the \n and CTCP (\1) character with \0 definition_string[len-1]='\0'; //definition_string[len-2]='\0'; // check if the given users version string has // the def string as a part of if - if so // return 1 - for action, else, carry on if (stristr(to_be_matched, definition_string)) { if (CTCPServLOGLEV > 1) { alog("VERSION MATCH: %s +[MATCHED WITH]+ %s", to_be_matched, definition_string); } fclose(OffDef); return 1; break; } } } else { alog("CRITICAL ERROR: Unable to open official.dat"); return 0; } if (CTCPServLOGLEV > 3) { alog("[ircd_ctcpversion] - Check against official.dat done."); } fclose(OffDef); return 0; } int CheckCustomDefList(char *to_be_matched) { FILE *CustomDef; char definition_string[128]; int len = 0; /* Open the file (r == in read only mode) */ CustomDef = fopen("custom.dat","r"); /* if the file is there, loop until there is no * more data to be read from the file */ if (CustomDef) { while (fgets(definition_string, 127, CustomDef) != NULL) { len = strlen(definition_string); /* replace the \n character with \0 */ definition_string[len-1]='\0'; //definition_string[len-2]='\0'; /* check if the given users version string has * the def string as a part of if - if so * return 1 - for action, else, carry on */ if (stristr(to_be_matched, definition_string)) { if (CTCPServLOGLEV > 1) { alog("VERSION MATCH: %s +[MATCHED WITH]+ %s", to_be_matched, definition_string); } fclose(CustomDef); return 1; break; } } } else { alog("CRITICAL ERROR: Unable to open custom.dat"); return 0; } if (CTCPServLOGLEV > 3) { alog("[ircd_ctcpversion] - Check against custom.dat done."); } fclose(CustomDef); return 0; } int kill_due_to_version(User *u) { char akillmask[BUFSIZE]; if (cTAKEACTION == 4) { #ifdef ccNOTICE1 notice(s_CTCPServ, u->nick, ccNOTICE1); #endif #ifdef ccNOTICE2 notice(s_CTCPServ, u->nick, ccNOTICE2); #endif #ifdef ccNOTICE3 notice(s_CTCPServ, u->nick, ccNOTICE3); #endif #ifdef ccNOTICE4 notice(s_CTCPServ, u->nick, ccNOTICE4); #endif #ifdef ccNOTICE5 notice(s_CTCPServ, u->nick, ccNOTICE5); #endif #ifdef ccNOTICE6 notice(s_CTCPServ, u->nick, ccNOTICE6); #endif #ifdef ccNOTICE7 notice(s_CTCPServ, u->nick, ccNOTICE7); #endif #ifdef ccNOTICE8 notice(s_CTCPServ, u->nick, ccNOTICE8); #endif #ifdef ccNOTICE9 notice(s_CTCPServ, u->nick, ccNOTICE9); #endif #ifdef ccNOTICE10 notice(s_CTCPServ, u->nick, ccNOTICE10); #endif return MOD_STOP; } if (cTAKEACTION == 3) { alog("WARNING: %s (%s) has a forbidden string in their CTCP VERSION reply", u->nick, u->host); return MOD_STOP; } if (cTAKEACTION == 2) { wallops(s_CTCPServ, "WARNING: %s (%s) has a forbidden string in their CTCP VERSION reply", u->nick, u->host); return MOD_STOP; } #ifdef cNOTICE1 notice(s_CTCPServ, u->nick, "%s", cNOTICE1); #endif #ifdef cNOTICE2 notice(s_CTCPServ, u->nick, "%s", cNOTICE2); #endif #ifdef cNOTICE3 notice(s_CTCPServ, u->nick, "%s", cNOTICE3); #endif #ifdef cNOTICE4 notice(s_CTCPServ, u->nick, "%s", cNOTICE4); #endif #ifdef cNOTICE5 notice(s_CTCPServ, u->nick, "%s", cNOTICE5); #endif #ifdef cNOTICE6 notice(s_CTCPServ, u->nick, "%s", cNOTICE6); #endif if (cTAKEACTION == 1) { if (cAKILLTIMEINSECONDS < 60) { /* 15 mins */ cAKILLTIMEINSECONDS = 900; } sprintf(akillmask, "*@%s", u->host); if ((cDONTUSEKILLCONESTIME == 1) || (!(KillClonesAkillExpire))) { add_akill(NULL, akillmask, s_CTCPServ, time(NULL) + cAKILLTIMEINSECONDS, cAKILLREASON); if (CTCPServLOGLEV > 0) { alog("AKILLING: %s -- *@%s [forbidden string in reply]", u->nick, u->host); } } else { add_akill(NULL, akillmask, s_CTCPServ, time(NULL) + KillClonesAkillExpire, cAKILLREASON); if (CTCPServLOGLEV > 0) { alog("AKILLING: %s -- *@%s [forbidden string in reply]", u->nick, u->host); } } if (!AkillOnAdd) { kill_user(s_CTCPServ, u->nick, cKILLREASON); return MOD_STOP; } } else { if (CTCPServLOGLEV > 0) { alog("KILLING: %s (%s) [forbidden string in reply]", u->nick, u->host); } kill_user(s_CTCPServ, u->nick, cKILLREASON); return MOD_STOP; } return MOD_STOP; } int my_ctcpserv_killrejoin(char *source, int ac, char **av) { if (ac != 2) { return MOD_STOP; } if (stricmp(av[0], s_CTCPServ) == 0) { if (CTCPServLOGLEV > 1) { alog("[ircd_ctcpversion] %s got KILLED, rejoining.", s_CTCPServ); } send_cmd(s_CTCPServ, "QUIT :Rejoin on kill loop protection."); NEWNICK(s_CTCPServ, s_CTCPServ, s_CTCPServHOST, s_CTCPServREALNAME, "+ioS", 1); return MOD_STOP; } return MOD_CONT; } #ifdef ACTION_NO_REPLY_USERS static int del_entry(CTCPU *fc) { if (fc->next) { fc->next->prev = fc->prev; } if (fc->prev) { fc->prev->next = fc->next; } else { ctcpuhash[tolower(*fc->nick)] = fc->next; } ctcpunum--; if (fc->nick) { free(fc->nick); } free(fc); return 1; } CTCPU *find_ctcpu_entry(char *nick) { CTCPU *fc; if (!nick || !*nick || !ctcpunum) { return NULL; } for (fc = ctcpuhash[tolower(*nick)]; fc; fc = fc->next) { if (!stricmp(nick, fc->nick)) { return fc; } } return NULL; } static CTCPU *create_entry(char *nick) { CTCPU *fc; fc = scalloc(sizeof(CTCPU), 1); if (fc == NULL) { alog("[ircd_ctcpversion] WARNING: COULD NOT ADD CHANNEL FREEZE RECORD! [Out of memory?]"); return NULL; } fc->nick = sstrdup(nick); fc->time = time(NULL); add_entry(fc); ctcpunum++; return fc; } static void add_entry(CTCPU *fc) { CTCPU *next, *prev; for (prev = NULL, next = ctcpuhash[tolower(*fc->nick)]; next != NULL && stricmp(next->nick, fc->nick) < 0; prev = next, next = next->next); fc->prev = prev; fc->next = next; if (!prev) { ctcpuhash[tolower(*fc->nick)] = fc; } else { prev->next = fc; } if (next) { next->prev = fc; } return; } #endif