Skip to content

Instantly share code, notes, and snippets.

@H7-25
Created May 23, 2014 00:04
Show Gist options
  • Save H7-25/9e86009530952f11ee0e to your computer and use it in GitHub Desktop.
Save H7-25/9e86009530952f11ee0e to your computer and use it in GitHub Desktop.
anope 1.8 ctcp version
#include "module.h"
#define AUTHOR "SGR"
#define VERSION "2.98"
#define MODNAME "ircd_ctcpversion"
/* -----------------------------------------------------------
* Name : ircd_ctcpserv
* Author: SGR <[email protected]>
* 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
*
*/
#undef 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 "Abilita il CTCP Version reply per connetterti a questo Network."
#define cNOTICE2 "Supporto http://support.simosnap.org"
/* #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 "Abilita il CTCP Version reply per connetterti a questo Network."
#define ccNOTICE2 "Supporto http://support.simosnap.org"
//#define ccNOTICE3 " "
//#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. */
#undef 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 "4s"
/* 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 "5s"
/* The reason with which clients are killed - MANDATORY */
#define KILL_REASON "Kline ID 301 - Info http://support.simosnap.org .";
/* The reason with which clients are Akilled - MANDATORY */
#define AKILL_REASON "Kline ID 301 - Info http://support.simosnap.org .";
/* 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 1
/* 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 3600 /* 1 minuto */
/* 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 = "services.simosnap.com";
/* 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 is_ctcpexempt(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;
int KillClonesAkillExpires = 0;
char *CTCPExempts = NULL;
char **CTCPExemptsList;
int CTCPExemptsNum = 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;
char *uid;
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, char *uid);
static CTCPU *find_ctcpu_entry(char *nick);
#endif
int AnopeInit(int argc, char **argv)
{
Message *msg = NULL;
int status, i;
char *s;
Directive directive = {"CTCPExempts", {{PARAM_STRING, PARAM_RELOAD, &CTCPExempts}}};
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);
alog("[ircd_ctcpserv] Created message for CLIENT command.");
#else
msg = createMessage("UID", my_nickA);
alog("[ircd_ctcpserv] Created message for UID command.");
#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, "+Iko", 1);
}
moduleAddAuthor(AUTHOR);
moduleAddVersion(VERSION);
donotchecktrue = cDEFAULTMODE;
CTCPServLOGLEV = cDEFAULTLOGLEVEL;
// caricamento delle exempts
moduleGetConfigDirective(&directive);
if (!(*(char **) (&directive)->params[0].ptr)) {
alog("[%s] ERROR: Missing configuration option '%s' - Please read %s.c before compiling", MODNAME, (&directive)->name, MODNAME);
}
if (CTCPExemptsNum) {
for (i = 0; i < CTCPExemptsNum; i++) {
free(CTCPExemptsList[i]);
}
}
if (CTCPExempts) {
CTCPExemptsNum = 0;
s = strtok(CTCPExempts, " ");
do {
if (s) {
CTCPExemptsNum++;
CTCPExemptsList = realloc(CTCPExemptsList, sizeof(char *) * CTCPExemptsNum);
CTCPExemptsList[CTCPExemptsNum - 1] = sstrdup(s);
}
} while ((s = strtok(NULL, " ")));
}
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)
{
int i;
if (CTCPExempts) free(CTCPExempts);
if (CTCPExemptsNum) {
for (i = 0; i < CTCPExemptsNum; i++) {
free(CTCPExemptsList[i]);
}
}
alog("[%s] Module Unloaded Successfully!", MODNAME);
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 ---- aggiunto TS6 da Simos*/
User *u;
Uid *ud = NULL;
char *s;
/* First, some basic checks */
if (ac != 2) { /* bleh */
return MOD_CONT;
}
if (ircd->ts6)
u = find_byuid(source); // If this is a ts6 ircd, find the user by uid
if (!u && !(u = finduser(source))) { // If user isn't found and we cant find them by nick, return
return MOD_CONT;
}
if (*msg[0] == '#') {
return MOD_CONT;
}
/* Channel message */
s = strchr(msg[0], '@');
if (s) {
*s++ = 0;
if (stricmp(s, ServerName) != 0) {
return MOD_CONT;
}
}
/*aggiunto*/
if (ircd->ts6)
ud = find_uid(s_CTCPServ); // Find CTCPServ UID
if ((stricmp(msg[0], s_CTCPServ)) == 0 || (ud && strcmp(msg[0], ud->uid) == 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 (ac < 2) {
if (CTCPServLOGLEV > 2) {
alog("CTCPServ [ircd_ctcpversion] ERROR - NICK/CLIENT/UID MSG LACKS NECESSARY ARGUMENTS");
}
return MOD_CONT;
}
if (CTCPServLOGLEV > 3) {
alog("[ircd_ctcpversion] - Found a new user :D");
}
#ifndef IRC_ULTIMATE3
if (*source) {
// commentato per testare su inspircd2.x
// 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 (ircd->ts6)
u2 = find_byuid(peep); // If this is a ts6 ircd, find the user by uid
if (!u2)
u2 = finduser(peep);
if (u2) {
if (donotchecktrue < 2 ) {
if (is_oper(u2)) {
if (CTCPServLOGLEV > 3) {
alog("[ircd_ctcpversion] %s - Not being checked (is an Oper)", u2->nick);
}
return MOD_CONT;
}
if (nick_identified(u2)) {
if (CTCPServLOGLEV > 3) {
alog("[ircd_ctcpversion] %s - Not being checked (is NickServ Identifed)", u2->nick);
}
return MOD_CONT;
}
/* if (is_svsagent(u2)) {
if (CTCPServLOGLEV > 3) {
alog("[ircd_ctcpversion] %s - Not being checked (is a Services Agent)", u2->nick);
}
return MOD_CONT;
}
*/
if (is_ctcpexempt(u2)) {
if (CTCPServLOGLEV > 3) {
alog("[ircd_ctcpversion] %s - Not being checked (is in exempts list)", u2->nick);
}
return MOD_CONT;
}
}
if (donotchecktrue) {
#ifdef ACTION_NO_REPLY_USERS
char CTCPidx[16];
char *argG[2];
#endif
if (CTCPServLOGLEV > 2) {
alog("[ircd_ctcpversion] Version Checking %s", u2->nick);
}
anope_cmd_privmsg(s_CTCPServ, u2->nick, "%cVERSION%c", 1, 1);
// lnx85: sostituisco il send_cmd con anope_cmd_privmsg (su 1.8.7 pare che send_cmd non faccia nulla)
// send_cmd(s_CTCPServ, "PRIVMSG %s :\1VERSION\1", u2->nick);
#ifdef ACTION_NO_REPLY_USERS
create_entry(u2->nick, ircd->ts6 ? u2->uid : NULL);
CTCPid = CTCPid + 1;
snprintf(CTCPidx, sizeof(CTCPidx), "NICK-%d", CTCPid);
if (CTCPid > 2147483600) {
CTCPid = 1;
}
argG[0] = sstrdup(u2->nick);
if (ircd->ts6)
argG[1] = sstrdup(u2->uid);
moduleAddCallback(CTCPidx, time(NULL)+dotime(NO_REPLY_TIMEOUT), timeout_kill_user,ircd->ts6 ? 2 : 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 (ircd->ts6)
u = find_byuid(moo->uid); // If this is a ts6 ircd, find the user by uid
if (!u)
u = finduser(moo->nick);
if (u) {
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;
/* Check empty version response */
while (isspace(*to_be_matched)) to_be_matched++;
if (strlen(to_be_matched) < 2) {
alog("[ircd_ctcpversion] - Empty version response.");
return 1;
}
/* 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 = 90;
}
sprintf(akillmask, "*@%s", u->host);
if ((cDONTUSEKILLCONESTIME == 1) || (!(KillClonesAkillExpires))) {
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) + KillClonesAkillExpires, 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);
}
if (fc->uid) {
free(fc->uid);
}
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) || !stricmp(nick, fc->uid)) {
return fc;
}
}
return NULL;
}
static CTCPU *create_entry(char *nick, char *uid)
{
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->uid = sstrdup(uid);
fc->time = time(NULL);
add_entry(fc);
ctcpunum++;
return fc;
}
int is_ctcpexempt(User *u)
{
int i, ret = 0;
char *buf, *buf2 = NULL;
buf = scalloc(strlen(u->username) + strlen(u->host) + 2, 1);
sprintf(buf, "%s@%s", u->username, u->host);
if (ircd->vhost) {
if (u->vhost) {
buf2 = scalloc(strlen(u->username) + strlen(u->vhost) + 2, 1);
sprintf(buf2, "%s@%s", u->username, u->vhost);
}
}
for (i = 0; i < CTCPExemptsNum; i++) {
if (strchr(CTCPExemptsList[i], '@') != NULL) {
if (match_wild_nocase(CTCPExemptsList[i], buf) || (ircd->vhost ? match_wild_nocase(CTCPExemptsList[i], buf2) : 0)) {
ret = 1;
}
} else {
if (match_wild_nocase(CTCPExemptsList[i], u->realname)) {
ret = 1;
}
}
}
free(buf);
if (ircd->vhost) {
free(buf2);
}
return ret;
}
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment