PDA

Tam Sürüm Bilgini Göster : Modul [adwords.c]


King_of_Night
05-10-2006, 20:12
/*
* ================================================== ================
* Filename: adwords.c
* Description: Anti-spam filtering
* Written by: AngryWolf <angrywolf@flashmail.com>
* Documentation: adwords.txt (comes with the package)
* ================================================== ================
* Note that this is a modified version of UnrealIRCd's built-in
* badword system which was written by the UnrealIRCd Team. This
* means that I copied & modified some codes from src/badwords.c and
* src/conf.c (they come with the Unreal3.2 package).
* ================================================== ================
*/

#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef STRIPBADWORDS
#include "badwords.h"
#endif
#ifdef _WIN32
#include "version.h"
#endif
#include "badwords.h"

extern void sendto_one(aClient *to, char *pattern, ...);
extern void sendto_serv_butone_token(aClient *one, char *prefix, char *command, char *token, char *pattern, ...);

// ================================================== ===============
// Macros
// ================================================== ===============

#define MSG_ADWORDS "ADWORDS"
#define TOK_ADWORDS "WO"
#define DEF_REGFLAGS (REG_ICASE | REG_EXTENDED)
#define BACKREF_TOKEN '\\'
#define IsAlpha(x) ((((x) >= 65) && ((x) <= 90)) || (((x) >= 97 ) && ((x) <= 122)))

#define ircfree(x) if (x) MyFree(x); x = NULL
#define ircstrdup(x,y) if (x) MyFree(x); if (!y) x = NULL; else x = strdup(y)
#define DelHook(x) if (x) HookDel(x); x = NULL
#define DelOverride(cmd, ovr) if (ovr && CommandExists(cmd)) CmdoverrideDel(ovr); ovr = NULL
#define DelCommand(x) if (x) CommandDel(x); x = NULL

#define DelAdwordChannel(a) DelListItem(a, AdwordsChannel); FreeAdword(a);
#define DelAdwordMessage(a) DelListItem(a, AdwordsMessage); FreeAdword(a);
#define DelAdwordQuit(a) DelListItem(a, AdwordsQuit); FreeAdword(a);
#ifdef HOOKTYPE_PRE_LOCAL_PART
#define DelAdwordPart(a) DelListItem(a, AdwordsPart); FreeAdword(a);
#endif

/* Default texts */
#define DEF_KILL_REASON "Yasaklanmis Kelimeyi Kullanan User Killenir.! (Advertising)"
#define DEF_BAN_REASON "Yasaklanmis Kelimeyi Kullanan User Banlanir.! (Advertising)"
#define DEF_BLOCK_MSG "Yasaklanmis Kelimeyi Kullanan User Bloacklanir.! (Advertising)"
#define DEF_WARNING_MSG "Yasaklanmis Kelimeyi Kullanan User Sizin Belirlemis Oldugunuz Kelimeye Dönüsüm Yaptirilir."

/* Ban types */
#ifndef BAN_ACT_KILL
#define NO_PLACE_HOST_BAN
/* For backward compatibility */
#define BAN_ACT_KILL 1
#define BAN_ACT_KLINE 4
#define BAN_ACT_ZLINE 5
#define BAN_ACT_GLINE 6
#define BAN_ACT_GZLINE 7
#else /* Unreal3.2-RC1 */
#undef NO_PLACE_HOST_BAN
#endif

/* Message types */
#define MT_ALL 0
#define MT_PRIVMSG 1
#define MT_NOTICE 2
#define MT_CTCP 3
#define MT_NONCTCP 4

/* Command types */
#define CT_PRIVMSG 0
#define CT_NOTICE 1
#define CT_PART 2
#define CT_QUIT 3

/* User types */
#define UT_ALL 0
#define UT_REG 1
#define UT_NONREG 2

/* Word types */
#define WT_REGEX 0x1
#define WT_FAST 0x2
#define WT_FAST_L 0x4
#define WT_FAST_R 0x8

/* Notification methods */
#define NM_PRIVATE 0x00
#define NM_CHANNEL 0x01

// ================================================== ===============
// Module header
// ================================================== ===============

ModuleHeader MOD_HEADER(adwords)
= {
"reklam",
"$Id: reklam.c,v 6.9 2005/03/28 15:31:52 angrywolf Exp Düzenleyen Unreal3.2.3'e Uyarlayan By oSSo $",
"Reklam Yasaklama Ve Filtreleme Modules",
"3.2-b8-1",
NULL
};

// ================================================== ===============
// Type definitions
// ================================================== ===============

typedef struct _adword Adword;
typedef struct _myconf MyConf;
typedef struct _chlist ChanList;

struct _adword
{
Adword *prev, *next;
char *word, *replace, *channel;
u_short type;
u_int notify:1, warn: 1, block:1, kill:1, ban:1;
u_int stoponmatch:1;
u_int msgtype:3, usertype:2;
regex_t *expr;
};

struct _myconf
{
u_int enable_adwords : 1;
u_int enable_notifications : 1;
u_int enable_bans : 1;
u_int enable_kills : 1;
u_int enable_blockings : 1;
u_int enable_warnings : 1;
u_int n_method : 1;
u_int require_mode_g : 1;
int ban_type: 4;
long ban_period;
char *channels;
char *kill_reason;
char *ban_reason;
char *block_message;
char *warning_message;
};

struct _chlist
{
ChanList *prev, *next;
char *channel;
};

// ================================================== ===============
// Function definitions & variable declarations
// ================================================== ===============

extern ConfigEntry *config_find_entry(ConfigEntry *ce, char *name);

static Command *AddCommand(Module *module, char *msg, char *token, iFP func);
static int m_adwords(aClient *cptr, aClient *sptr, int parc, char *parv[]);
static int cb_config_test(ConfigFile *, ConfigEntry *, int, int *);
static int cb_config_run(ConfigFile *, ConfigEntry *, int);
static int cb_config_rehash();
static char *cb_privmsg(aClient *, aClient *, aClient *, char *, int);
static char *cb_chanmsg(aClient *, aClient *, aChannel *, char *, int);
static char *cb_quit(aClient *sptr, char *comment);
#ifdef HOOKTYPE_PRE_LOCAL_PART
static char *cb_partmsg(aClient *sptr, aChannel *chptr, char *comment);
#endif
#ifndef HOOKTYPE_PRE_LOCAL_QUIT
static Cmdoverride *AddOverride(char *msg, iFP cb);
static int override_quit(Cmdoverride *, aClient *, aClient *, int, char *[]);
#endif
static void adwords_event_kill(char *name);
static void stats_wordlist(aClient *sptr, Adword *wordlist, char wtype);
static char *find_CmdType(u_int type);
static char *find_BanType(int type);
#ifdef NO_PLACE_HOST_BAN
static char *find_BanFlag(int type);
#endif
static char find_MsgType(u_int type);
static char find_WordFlag(u_int type);

static Hook *HookConfTest, *HookConfRun, *HookConfRehash;
static Hook *HookPrivMsg = NULL, *HookChanMsg = NULL;
#ifdef HOOKTYPE_PRE_LOCAL_PART
static Hook *HookPrePart = NULL;
#endif
#ifdef HOOKTYPE_PRE_LOCAL_QUIT
static Hook *HookPreQuit = NULL;
#endif

Adword *AdwordsMessage = NULL, *AdwordsChannel = NULL, *AdwordsQuit = NULL;
#ifdef HOOKTYPE_PRE_LOCAL_PART
Adword *AdwordsPart = NULL;
#endif

ConfigItem_except *conf_exceptchan;
MyConf myconf;
static char nickbuf[NICKLEN+1];
Command *CmdAdwords;
#ifndef HOOKTYPE_PRE_LOCAL_QUIT
Cmdoverride *OvrQuit;
#endif

#ifndef STATIC_LINKING
static ModuleInfo *MyModInfo;
#define MyMod MyModInfo->handle
#define SAVE_MODINFO MyModInfo = modinfo;
#else
#define MyMod NULL
#define SAVE_MODINFO
#endif

// ================================================== ===============
// Functions related to the Adword struct
// ================================================== ===============

static void FreeAdword(Adword *a)
{
MyFree(a->word);
ircfree(a->replace);
ircfree(a->channel);
if (a->expr)
{
regfree(a->expr);
MyFree(a->expr);
}

MyFree(a);
}

static Adword *adword_duplicate(Adword *a, int regflags)
{
Adword *x;

x = (Adword *) MyMalloc(sizeof(Adword));
memcpy(x, a, sizeof(Adword));
x->word = strdup(a->word);
if (a->replace)
x->replace = strdup(a->replace);
if (a->channel)
x->channel = strdup(a->channel);
if (a->expr)
{
x->expr = (regex_t *) MyMallocEx(sizeof(regex_t));
regcomp(x->expr, x->word, regflags);
}

return x;
}

static void AddExceptChan(char *mask)
{
ConfigItem_except *e;

e = (ConfigItem_except *) MyMallocEx(sizeof(ConfigItem_except));
e->mask = strdup(mask);

AddListItem(e, conf_exceptchan);
}

// ================================================== ===============
// Functions related to loading/unloading configuration
// ================================================== ===============

static void InitConf()
{
memset(&myconf, 0, sizeof myconf);
memset(&nickbuf, 0, sizeof nickbuf);

myconf.ban_type = BAN_ACT_KLINE;
myconf.ban_period = 3600; /* 1h */
conf_exceptchan = NULL;
}

static void FreeConf()
{
Adword *a;
ListStruct *next;
ConfigItem_except *e;

/* myconf */

if (myconf.channels)
MyFree(myconf.channels);
if (myconf.kill_reason)
MyFree(myconf.kill_reason);
if (myconf.ban_reason)
MyFree(myconf.ban_reason);
if (myconf.block_message)
MyFree(myconf.block_message);
if (myconf.warning_message)
MyFree(myconf.warning_message);

/* adwords */

for (a = AdwordsChannel; a; a = (Adword *) next)
{
next = (ListStruct *) a->next;
DelAdwordChannel(a);
}
for (a = AdwordsMessage; a; a = (Adword *) next)
{
next = (ListStruct *) a->next;
DelAdwordMessage(a);
}
for (a = AdwordsQuit; a; a = (Adword *) next)
{
next = (ListStruct *) a->next;
DelAdwordQuit(a);
}
#ifdef HOOKTYPE_PRE_LOCAL_PART
for (a = AdwordsPart; a; a = (Adword *) next)
{
next = (ListStruct *) a->next;
DelAdwordPart(a);
}
#endif
/* channel exceptions */

for (e = conf_exceptchan; e; e = (ConfigItem_except *) next)
{
next = (ListStruct *) e->next;
DelListItem(e, conf_exceptchan);
MyFree(e->mask);
MyFree(e);
}
}

// ================================================== ===============
// Module functions
// ================================================== ===============

DLLFUNC int MOD_TEST(adwords)(ModuleInfo *modinfo)
{
SAVE_MODINFO
HookConfTest = HookAddEx(modinfo->handle, HOOKTYPE_CONFIGTEST, cb_config_test);

return MOD_SUCCESS;
}

DLLFUNC int MOD_INIT(adwords)(ModuleInfo *modinfo)
{
SAVE_MODINFO
InitConf();

CmdAdwords = AddCommand(modinfo->handle, MSG_ADWORDS, TOK_ADWORDS, m_adwords);
HookConfRun = HookAddEx(modinfo->handle, HOOKTYPE_CONFIGRUN, cb_config_run);
HookConfRehash = HookAddEx(modinfo->handle, HOOKTYPE_REHASH, cb_config_rehash);

if (!CmdAdwords)
return MOD_FAILED;

HookPrivMsg = HookAddPCharEx(modinfo->handle, HOOKTYPE_USERMSG, cb_privmsg);
HookChanMsg = HookAddPCharEx(modinfo->handle, HOOKTYPE_CHANMSG, cb_chanmsg);
#ifdef HOOKTYPE_PRE_LOCAL_PART
HookPrePart = HookAddPCharEx(modinfo->handle, HOOKTYPE_PRE_LOCAL_PART, cb_partmsg);
#endif
#ifdef HOOKTYPE_PRE_LOCAL_QUIT
HookPreQuit = HookAddPCharEx(modinfo->handle, HOOKTYPE_PRE_LOCAL_QUIT, cb_quit);
#endif

return MOD_SUCCESS;
}

DLLFUNC int MOD_LOAD(adwords)(int module_load)
{
#ifndef HOOKTYPE_PRE_LOCAL_QUIT
if (!(OvrQuit = AddOverride("quit", override_quit)))
return MOD_FAILED;
#endif

return MOD_SUCCESS;
}

DLLFUNC int MOD_UNLOAD(adwords)(int module_unload)
{
FreeConf();

#ifdef HOOKTYPE_PRE_LOCAL_PART
DelHook(HookPrePart);
#endif
DelHook(HookChanMsg);
DelHook(HookPrivMsg);
DelHook(HookConfRehash);
DelHook(HookConfRun);
DelHook(HookConfTest);

#ifndef HOOKTYPE_PRE_LOCAL_QUIT
DelOverride("quit", OvrQuit);
#endif
DelCommand(CmdAdwords);

return MOD_SUCCESS;
}

// ================================================== ===============
// Types
// ================================================== ===============

static char *find_CmdType(u_int type)
{
switch(type)
{
case CT_PRIVMSG: return "PRIVMSG";
case CT_NOTICE: return "NOTICE";
case CT_PART: return "PART";
case CT_QUIT: return "QUIT";
}

return "???";
}

static char find_MsgType(u_int type)
{
switch(type)
{
case MT_ALL: return 'a';
case MT_PRIVMSG: return 'p';
case MT_NOTICE: return 'n';
case MT_CTCP: return 'C';
case MT_NONCTCP: return 'N';
}

return '?';
}

static char find_WordFlag(u_int type)
{
if (type & WT_FAST)
return 'F';
else if (type & WT_REGEX)
return 'R';

return '?';
}

static char find_UserType(u_int type)
{
switch(type)
{
case UT_ALL: return 'a';
case UT_REG: return 'r';
case UT_NONREG: return 'n';
}

return '?';
}

static char *find_BanType(int type)
{
switch(type)
{
case BAN_ACT_KLINE: return "kline";
case BAN_ACT_GLINE: return "gline";
case BAN_ACT_ZLINE: return "zline";
case BAN_ACT_GZLINE: return "gzline";
}

return "<none>";
}

#ifdef NO_PLACE_HOST_BAN
static char *find_BanFlag(int type)
{
switch(type)
{
case BAN_ACT_KLINE: return "k";
case BAN_ACT_GLINE: return "G";
case BAN_ACT_ZLINE: return "z";
case BAN_ACT_GZLINE: return "Z";
}

return NULL;
}
#endif

static char *make_optlist(Adword *a)
{
static char buf[11];
char *p = buf;

if (a->notify) *(p++) = 'n';
if (a->warn) *(p++) = 'w';
if (a->block) *(p++) = 'b';
if (a->kill) *(p++) = 'k';
if (a->ban) *(p++) = 'B';
if (a->stoponmatch) *(p++) = 's';
if (p == buf) *(p++) = '*';

*p = 0;

return buf;
}

// ================================================== ===============
// Misc stuff
// ================================================== ===============

static Command *AddCommand(Module *module, char *msg, char *token, iFP func)
{
Command *cmd;

if (CommandExists(msg))
{
config_error("Command %s already exists", msg);
return NULL;
}
if (CommandExists(token))
{
config_error("Token %s already exists", token);
return NULL;
}

cmd = CommandAdd(module, msg, token, func, MAXPARA, 0);

#ifndef STATIC_LINKING
if (ModuleGetError(module) != MODERR_NOERROR || !cmd)
#else
if (!cmd)
#endif
{
#ifndef STATIC_LINKING
config_error("Error adding command %s: %s", msg,
ModuleGetErrorStr(module));
#else
config_error("Error adding command %s", msg);
#endif
return NULL;
}

return cmd;
}

#ifndef HOOKTYPE_PRE_LOCAL_QUIT
static Cmdoverride *AddOverride(char *msg, iFP cb)
{
Cmdoverride *ovr = CmdoverrideAdd(MyMod, msg, cb);

#ifndef STATIC_LINKING
if (ModuleGetError(MyMod) != MODERR_NOERROR || !ovr)
#else
if (!ovr)
#endif
{
#ifndef STATIC_LINKING
config_error("Error replacing command %s when loading module %s: %s",
msg, MOD_HEADER(adwords).name, ModuleGetErrorStr(MyMod));
#else
config_error("Error replacing command %s when loading module %s",
msg, MOD_HEADER(adwords).name);
#endif
return NULL;
}

return ovr;
}
#endif

static u_int check_type(char *word)
{
/*
* This code originally comes from src/s_conf.c,
* with some modifications.
*/

u_int type = WT_FAST, fasttype = 0;
char *p;

for (p = word; *p; p++)
{
/*
* I use my own check for alphabetic characters.
* The old one accepted character codes between
* 65 and 123. That means ABCDEFGHIJKLMNOPQRSTU
* WXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{ were
* accepted. I don't want this.
*/
if (!IsAlpha(*p))
{
if ((word == p) && (*p == '*'))
{
/* Asterisk at the left */
fasttype |= WT_FAST_L;
continue;
}
if ((p[1] == 0) && (*p == '*'))
{
/* Asterisk at the right */
fasttype |= WT_FAST_R;
continue;
}
type = WT_REGEX;
break;
}
}

if (type != WT_REGEX)
type |= fasttype;

return type;
}

static u_int check_regex(ConfigEntry *ce_word)
{
/*
* This code originally comes from src/s_conf.c,
* with some modifications.
*/

int errorcode, errorbufsize;
u_int errors = 0;
char *errorbuf;
regex_t *expr;

expr = (regex_t *) MyMallocEx(sizeof(regex_t));
errorcode = regcomp(expr, ce_word->ce_vardata, DEF_REGFLAGS);
if (errorcode > 0)
{
errorbufsize = regerror(errorcode, expr, NULL, 0)+1;
errorbuf = MyMalloc(errorbufsize);
regerror(errorcode, expr, errorbuf, errorbufsize);
config_error("%s:%i: adwords::adword::%s contains an invalid regex: %s",
ce_word->ce_fileptr->cf_filename,
ce_word->ce_varlinenum,
ce_word->ce_varname, errorbuf);
errors++;
MyFree(errorbuf);
}
regfree(expr);
MyFree(expr);

return errors;
}

static char *find_backref(char *string)
{
char *p;

for (p = string; *p; p++)
{
if (p[0] == BACKREF_TOKEN)
{
if (p != string && p[-1] == BACKREF_TOKEN)
continue;
if (p[1] >= '1' && p[1] <= '9')
return p;
}
}

return NULL;
}

static char *dump_fastword(u_int type, char *word)
{
u_int wlength;
char *wtmp, *p, *q;

wlength = strlen(word) + 1;
if (type & WT_FAST_L)
wlength--;
if (type & WT_FAST_R)
wlength--;

q = wtmp = (char *) MyMalloc(wlength);
for (p = word; *p; p++)
if (*p != '*')
*(q++) = *p;
*q = '\0';

return wtmp;
}

// ================================================== ===============
// Config file interfacing
// ================================================== ===============

static int cb_config_rehash()
{
FreeConf();
InitConf();

return 1;
}

static int cb_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
{
ConfigEntry *ce_matchtype, *ce_word, *ce_replace, *cep, *cepp;
int errors = 0;
u_int matchtype;

if (type != CONFIG_MAIN)
return 0;

if (!strcmp(ce->ce_varname, "adwords"))
{
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
{
if (!cep->ce_varname)
{
config_error("%s:%i: blank adwords item",
cep->ce_fileptr->cf_filename,
cep->ce_varlinenum);
errors++;
}
else if (!strcmp(cep->ce_varname, "enable"))
{
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
if (!cepp->ce_varname)
{
config_error("%s:%i: blank adwords::enable item",
cepp->ce_fileptr->cf_filename,
cepp->ce_varlinenum);
errors++;
continue;
}
if (!strcmp(cepp->ce_varname, "adwords"))
;
else if (!strcmp(cepp->ce_varname, "bans"))
;
else if (!strcmp(cepp->ce_varname, "kills"))
;
else if (!strcmp(cepp->ce_varname, "blockings"))
;
else if (!strcmp(cepp->ce_varname, "notifications"))
;
else if (!strcmp(cepp->ce_varname, "warnings"))
;
else
{
config_error("%s:%i: unknown directive adwords::enable::%s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
cepp->ce_varname);
errors++;
}
}
}
else if (!cep->ce_vardata)
{
config_error("%s:%i: adwords::%s item without value",
cep->ce_fileptr->cf_filename,
cep->ce_varlinenum, cep->ce_varname);
errors++;
}
else if (!strcmp(cep->ce_varname, "adword"))
{
matchtype = 0;

if (!strcmp(cep->ce_vardata, "all"))
;
else if (!strcmp(cep->ce_vardata, "message"))
;
else if (!strcmp(cep->ce_vardata, "channel"))
;
else if (!strcmp(cep->ce_vardata, "quit"))
;
#ifdef HOOKTYPE_PRE_LOCAL_PART
else if (!strcmp(cep->ce_vardata, "part"))
;
#endif
else
{
config_error("%s:%i: unknown adwords::adword type %s",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
cep->ce_vardata);
errors++;
continue;
}

/* matchtype */
if ((ce_matchtype = config_find_entry(cep->ce_entries, "matchtype")))
{
if (!ce_matchtype->ce_vardata)
{
config_error("%s:%i: adwords::adword::matchtype without contents",
ce_matchtype->ce_fileptr->cf_filename,
ce_matchtype->ce_varlinenum);
errors++;
continue;
}

if (!strcmp(ce_matchtype->ce_vardata, "regex"))
matchtype = WT_REGEX;
else if (!strcmp(ce_matchtype->ce_vardata, "fast"))
matchtype = WT_FAST;
else if (!strcmp(ce_matchtype->ce_vardata, "auto"))
;
else
{
config_error("%s:%i: unknown adwords::adword::matchtype %s",
ce_matchtype->ce_fileptr->cf_filename,
ce_matchtype->ce_varlinenum,
ce_matchtype->ce_vardata);
errors++;
continue;
}
}

/* word */
if (!(ce_word = config_find_entry(cep->ce_entries, "word")))
{
config_error("%s:%i: adwords::adword without word item",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
errors++;
continue;
}
else if (!ce_word->ce_vardata)
{
config_error("%s:%i: adwords::adword::word without contents",
ce_word->ce_fileptr->cf_filename, ce_word->ce_varlinenum);
errors++;
continue;
}
else
{
u_int wordtype = check_type(ce_word->ce_vardata);

if (!matchtype)
;
else if (matchtype & WT_FAST)
{
if (wordtype & WT_REGEX)
{
config_error("%s:%i: adwords::adword::word contains invalid data (the fast badword replace system can do: \"blah\", \"*blah\", \"blah*\" and \"*blah*\", in all other cases use regex)",
ce_word->ce_fileptr->cf_filename,
ce_word->ce_varlinenum);
errors++;
}
}
else
errors += check_regex(ce_word);

if (errors)
continue;
}

/* replace */
if ((ce_replace = config_find_entry(ce->ce_entries, "replace")))
{
if (!ce_replace->ce_vardata)
{
config_error("%s:%i: adwords::adword::replace without contents",
ce_replace->ce_fileptr->cf_filename,
ce_replace->ce_varlinenum);
errors++;
}
}

for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
if (!cepp->ce_varname)
{
config_error("%s:%i: blank adwords::adword item",
cepp->ce_fileptr->cf_filename,
cepp->ce_varlinenum);
errors++;
continue;
}
if (!strcmp(cepp->ce_varname, "notify"))
;
else if (!strcmp(cepp->ce_varname, "warn"))
;
else if (!strcmp(cepp->ce_varname, "block"))
;
else if (!strcmp(cepp->ce_varname, "kill"))
;
else if (!strcmp(cepp->ce_varname, "ban"))
;
else if (!strcmp(cepp->ce_varname, "stoponmatch"))
;
else if (!cepp->ce_vardata)
{
config_error("%s:%i: adwords::adword::%s item without value",
cepp->ce_fileptr->cf_filename,
cepp->ce_varlinenum, cepp->ce_varname);
errors++;
continue;
}
else if (!strcmp(cepp->ce_varname, "matchtype"))
;
else if (!strcmp(cepp->ce_varname, "word"))
;
else if (!strcmp(cepp->ce_varname, "replace"))
;
else if (!strcmp(cepp->ce_varname, "channel"))
;
else if (!strcmp(cepp->ce_varname, "msgtype"))
{
if (!strcmp(cepp->ce_vardata, "all"))
;
else if (!strcmp(cepp->ce_vardata, "privmsg"))
;
else if (!strcmp(cepp->ce_vardata, "notice"))
;
else if (!strcmp(cepp->ce_vardata, "ctcp"))
;
else if (!strcmp(cepp->ce_vardata, "non-ctcp"))
;
else
{
config_error("%s:%i: unknown adwords::adword::msgtype %s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
cepp->ce_vardata);
errors++;
}
}
else if (!strcmp(cepp->ce_varname, "usertype"))
{
if (!strcmp(cepp->ce_vardata, "all"))
;
else if (!strcmp(cepp->ce_vardata, "registered"))
;
else if (!strcmp(cepp->ce_vardata, "non-registered"))
;
else
{
config_error("%s:%i: unknown adwords::adword::usertype %s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
cepp->ce_vardata);
errors++;
}
}
else
{
config_error("%s:%i: unknown directive adwords::adword::%s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
cepp->ce_varname);
errors++;
}
}
}
else if (!strcmp(cep->ce_varname, "notification-channels"))
;
else if (!strcmp(cep->ce_varname, "notification-method"))
{
if (!strcmp(cep->ce_vardata, "channel"))
;
else if (!strcmp(cep->ce_vardata, "private"))
;
else
{
config_error("%s:%i: unknown notification method %s",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
cep->ce_vardata);
errors++;
}
}
else if (!strcmp(cep->ce_varname, "require-mode-g"))
;
else if (!strcmp(cep->ce_varname, "kill-reason"))
;
else if (!strcmp(cep->ce_varname, "ban-reason"))
;
else if (!strcmp(cep->ce_varname, "block-message"))
;
else if (!strcmp(cep->ce_varname, "warning-message"))
;
else if (!strcmp(cep->ce_varname, "ban-type"))
{
if (!strcmp(cep->ce_vardata, "kline"))
;
else if (!strcmp(cep->ce_vardata, "gline"))
;
else if (!strcmp(cep->ce_vardata, "zline"))
;
else if (!strcmp(cep->ce_vardata, "gzline"))
;
else
{
config_error("%s:%i: unknown ban type %s",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
cep->ce_vardata);
errors++;
}
}
else if (!strcmp(cep->ce_varname, "ban-period"))
;
else if (!strcmp(cep->ce_varname, "except"))
{
if (!strcmp(cep->ce_vardata, "channel"))
{
if (!config_find_entry(cep->ce_entries, "mask"))
{
config_error("%s:%i: adwords::except channel without mask item",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
errors++;
continue;
}
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
if (!cepp->ce_vardata)
{
config_error("%s:%i: adwords::except channel item without contents",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
errors++;
continue;
}
if (!strcmp(cepp->ce_varname, "mask"))
;
else
{
config_error("%s:%i: unknown adwords::except channel directive %s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname);
errors++;
continue;
}
}
}
}
else
{
config_error("%s:%i: unknown directive adwords::%s",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
cep->ce_varname);
errors++;
}
}
*errs = errors;
return errors ? -1 : 1;
}
else
return 0;
}

static int cb_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
{
ConfigEntry *cep, *cepp;

if (type != CONFIG_MAIN)
return 0;

if (!strcmp(ce->ce_varname, "adwords"))
{
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
{
if (!strcmp(cep->ce_varname, "enable"))
{
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
if (!strcmp(cepp->ce_varname, "adwords"))
myconf.enable_adwords = config_checkval(cepp->ce_vardata, CFG_YESNO);
else if (!strcmp(cepp->ce_varname, "bans"))
myconf.enable_bans = config_checkval(cepp->ce_vardata, CFG_YESNO);
else if (!strcmp(cepp->ce_varname, "kills"))
myconf.enable_kills = config_checkval(cepp->ce_vardata, CFG_YESNO);
else if (!strcmp(cepp->ce_varname, "blockings"))
myconf.enable_blockings = config_checkval(cepp->ce_vardata, CFG_YESNO);
else if (!strcmp(cepp->ce_varname, "notifications"))
myconf.enable_notifications = config_checkval(cepp->ce_vardata, CFG_YESNO);
else if (!strcmp(cepp->ce_varname, "warnings"))
myconf.enable_warnings = config_checkval(cepp->ce_vardata, CFG_YESNO);
}
}
else if (!strcmp(cep->ce_varname, "notification-channels"))
{
ircstrdup(myconf.channels, cep->ce_vardata);
}
else if (!strcmp(cep->ce_varname, "notification-method"))
{
if (!strcmp(cep->ce_vardata, "channel"))
myconf.n_method = NM_CHANNEL;
else if (!strcmp(cep->ce_vardata, "private"))
myconf.n_method = NM_PRIVATE;
}
else if (!strcmp(cep->ce_varname, "kill-reason"))
{
if (strcmp(cep->ce_vardata, "no"))
{
ircstrdup(myconf.kill_reason, cep->ce_vardata);
}
}
else if (!strcmp(cep->ce_varname, "ban-reason"))
{
if (strcmp(cep->ce_vardata, "no"))
{
ircstrdup(myconf.ban_reason, cep->ce_vardata);
}
}
else if (!strcmp(cep->ce_varname, "block-message"))
{
if (strcmp(cep->ce_vardata, "no"))
{
ircstrdup(myconf.block_message, cep->ce_vardata);
}
}
else if (!strcmp(cep->ce_varname, "warning-message"))
{
if (strcmp(cep->ce_vardata, "no"))
{
ircstrdup(myconf.warning_message, cep->ce_vardata);
}
}
else if (!strcmp(cep->ce_varname, "require-mode-g"))
myconf.require_mode_g = config_checkval(cep->ce_vardata, CFG_YESNO);
else if (!strcmp(cep->ce_varname, "ban-period"))
myconf.ban_period = config_checkval(cep->ce_vardata, CFG_TIME);
else if (!strcmp(cep->ce_varname, "ban-type"))
{
if (!strcmp(cep->ce_vardata, "kline"))
myconf.ban_type = BAN_ACT_KLINE;
else if (!strcmp(cep->ce_vardata, "gline"))
myconf.ban_type = BAN_ACT_GLINE;
else if (!strcmp(cep->ce_vardata, "zline"))
myconf.ban_type = BAN_ACT_ZLINE;
else if (!strcmp(cep->ce_vardata, "gzline"))
myconf.ban_type = BAN_ACT_GZLINE;
}
else if (!strcmp(cep->ce_varname, "except"))
{
if (!strcmp(cep->ce_vardata, "channel"))
{
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
if (!strcmp(cepp->ce_varname, "mask"))
AddExceptChan(cepp->ce_vardata);
}
}
else if (!strcmp(cep->ce_varname, "adword"))
{
ConfigEntry *ce_matchtype, *ce_word, *ce_block;
Adword *a;
int regflags;

regflags = DEF_REGFLAGS;
a = (Adword *) MyMallocEx(sizeof(Adword));

/* block */
if ((ce_block = config_find_entry(cep->ce_entries, "block")))
{
a->block = 1;
regflags |= REG_NOSUB;
}

/* matchtype */
if ((ce_matchtype = config_find_entry(cep->ce_entries, "matchtype")))
{
if (!strcmp(ce_matchtype->ce_vardata, "regex"))
a->type = WT_REGEX;
else if (!strcmp(ce_matchtype->ce_vardata, "fast"))
a->type = WT_FAST;
}

/* word */
if ((ce_word = config_find_entry(cep->ce_entries, "word")))
{
if (!a->type)
a->type = check_type(ce_word->ce_vardata);

if (a->type & WT_REGEX)
{
ircstrdup(a->word, ce_word->ce_vardata);
a->expr = (regex_t *) MyMallocEx(sizeof(regex_t));
regcomp(a->expr, a->word, regflags);
}
else
{
/* We have to do this twice (because of "matchtype fast") */
a->type = check_type(ce_word->ce_vardata);
a->word = dump_fastword(a->type, ce_word->ce_vardata);
}
}

for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
if (!strcmp(cepp->ce_varname, "word"))
;
else if (!strcmp(cepp->ce_varname, "block"))
;
else if (!strcmp(cepp->ce_varname, "replace"))
{
ircstrdup(a->replace, cepp->ce_vardata);
}
else if (!strcmp(cepp->ce_varname, "channel"))
{
ircstrdup(a->channel, cepp->ce_vardata);
}
else if (!strcmp(cepp->ce_varname, "notify"))
a->notify = 1;
else if (!strcmp(cepp->ce_varname, "warn"))
a->warn = 1;
else if (!strcmp(cepp->ce_varname, "kill"))
a->kill = 1;
else if (!strcmp(cepp->ce_varname, "ban"))
a->ban = 1;
else if (!strcmp(cepp->ce_varname, "stoponmatch"))
a->stoponmatch = 1;
else if (!strcmp(cepp->ce_varname, "msgtype"))
{
if (!strcmp(cepp->ce_vardata, "all"))
a->msgtype = MT_ALL;
else if (!strcmp(cepp->ce_vardata, "privmsg"))
a->msgtype = MT_PRIVMSG;
else if (!strcmp(cepp->ce_vardata, "notice"))
a->msgtype = MT_NOTICE;
else if (!strcmp(cepp->ce_vardata, "ctcp"))
a->msgtype = MT_CTCP;
else if (!strcmp(cepp->ce_vardata, "non-ctcp"))
a->msgtype = MT_NONCTCP;
}
else if (!strcmp(cepp->ce_varname, "usertype"))
{
if (!strcmp(cepp->ce_vardata, "all"))
a->usertype = UT_ALL;
else if (!strcmp(cepp->ce_vardata, "registered"))
a->usertype = UT_REG;
else if (!strcmp(cepp->ce_vardata, "non-registered"))
a->usertype = UT_NONREG;
}
}

if (!strcmp(cep->ce_vardata, "message"))
{
AddListItem(a, AdwordsMessage);
}
else if (!strcmp(cep->ce_vardata, "channel"))
{
AddListItem(a, AdwordsChannel);
}
else if (!strcmp(cep->ce_vardata, "quit"))
{
AddListItem(a, AdwordsQuit);
}
#ifdef HOOKTYPE_PRE_LOCAL_PART
else if (!strcmp(cep->ce_vardata, "part"))
{
AddListItem(a, AdwordsPart);
}
#endif
else if (!strcmp(cep->ce_vardata, "all"))
{
AddListItem(a, AdwordsMessage);
AddListItem(adword_duplicate(a, regflags), AdwordsChannel);
AddListItem(adword_duplicate(a, regflags), AdwordsQuit);
#ifdef HOOKTYPE_PRE_LOCAL_PART
AddListItem(adword_duplicate(a, regflags), AdwordsPart);
#endif
}
}
}
}

return 0;
}

static int cb_stats(aClient *sptr)
{
sendto_one(sptr, ":%s %i %s :enable::adwords: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_adwords);
sendto_one(sptr, ":%s %i %s :enable::bans: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_bans);
sendto_one(sptr, ":%s %i %s :enable::kills: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_kills);
sendto_one(sptr, ":%s %i %s :enable::blockings: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_blockings);
sendto_one(sptr, ":%s %i %s :enable::notifications: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_notifications);
sendto_one(sptr, ":%s %i %s :enable::warnings: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_warnings);
sendto_one(sptr, ":%s %i %s :require-mode-g: %d",
me.name, RPL_TEXT, sptr->name, myconf.require_mode_g);
sendto_one(sptr, ":%s %i %s :notification-method: %s",
me.name, RPL_TEXT, sptr->name, (myconf.n_method == NM_PRIVATE) ? "private" : (myconf.n_method == NM_CHANNEL) ? "channel" : "<unknown>");
sendto_one(sptr, ":%s %i %s :notification-channels: %s",
me.name, RPL_TEXT, sptr->name, myconf.channels ? myconf.channels : "<none>");
sendto_one(sptr, ":%s %i %s :kill-reason: %s",
me.name, RPL_TEXT, sptr->name, myconf.kill_reason ? myconf.kill_reason : DEF_KILL_REASON);
sendto_one(sptr, ":%s %i %s :ban-reason: %s",
me.name, RPL_TEXT, sptr->name, myconf.ban_reason ? myconf.ban_reason : DEF_BAN_REASON);
sendto_one(sptr, ":%s %i %s :block-message: %s",
me.name, RPL_TEXT, sptr->name, myconf.block_message ? myconf.block_message : DEF_BLOCK_MSG);
sendto_one(sptr, ":%s %i %s :warning-message: %s",
me.name, RPL_TEXT, sptr->name, myconf.warning_message ? myconf.warning_message : DEF_WARNING_MSG);
sendto_one(sptr, ":%s %i %s :ban-type: %s",
me.name, RPL_TEXT, sptr->name, find_BanType(myconf.ban_type));
sendto_one(sptr, ":%s %i %s :ban-period: %s",
me.name, RPL_TEXT, sptr->name, pretty_time_val(myconf.ban_period));

sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, sptr->name, 'S');
return 0;
}

#ifdef NO_PLACE_HOST_BAN
void ban_client(aClient *cptr, char *type, long period, char *reason)
{
char hostip[128], mo[100], mo2[100];
char *tkllayer[9] = {
me.name, /*0 server.name */
"+", /*1 +|- */
type, /*2 ban type */
"*", /*3 user */
NULL, /*4 host */
NULL,
NULL, /*6 expire_at */
NULL, /*7 set_at */
NULL /*8 reason */
};

strlcpy(hostip, Inet_ia2p(&cptr->ip), sizeof(hostip));

tkllayer[4] = hostip;
tkllayer[5] = me.name;
ircsprintf(mo, "%li", period + TStime());
ircsprintf(mo2, "%li", TStime());
tkllayer[6] = mo;
tkllayer[7] = mo2;
tkllayer[8] = reason;

m_tkl(&me, &me, 9, tkllayer);
return;
}
#endif

/*
* These stuffs are from src/badwords.c,
* I modified them for my own purposes
*/

#ifndef SPAMFILTER_BAN_TIME
static char *our_strcasestr(char *haystack, char *needle)
{
int i;
int nlength = strlen (needle);
int hlength = strlen (haystack);

if (nlength > hlength) return NULL;
if (hlength <= 0) return NULL;
if (nlength <= 0) return haystack;

for (i = 0; i <= (hlength - nlength); i++) {
if (strncasecmp (haystack + i, needle, nlength) == 0)
return haystack + i;
}

return NULL;
}
#endif

inline int my_fast_badword_match(Adword *adword, char *line)
{
char *p;
int bwlen = strlen(adword->word);
if ((adword->type & WT_FAST_L) && (adword->type & WT_FAST_R))
return (our_strcasestr(line, adword->word) ? 1 : 0);

p = line;
while((p = our_strcasestr(p, adword->word)))
{
if (!(adword->type & WT_FAST_L))
{
if ((p != line) && isalnum(*(p - 1)))
goto next;
}
if (!(adword->type & WT_FAST_R))
{
if (isalnum(*(p + bwlen)))
goto next;
}
return 1;
next:
p += bwlen;
}
return 0;
}

/*
* This code comes from src/badwords.c (fast_badword_replace
* which was written by Syzop), I modified it a bit.
* (Also made speed optimizations.)
*/

inline int my_fast_badword_replace(Adword *adword, char *line, char *buf, int max)
{
char *searchw = adword->word, *replacew = adword->replace;
char *pold = line, *pnew = buf;
char *poldx = line;
char *startw, *endw;
char *c_eol = buf + max - 1;
int replacen, searchn;
int cleaned = 0;

replacen = strlen(replacew);
searchn = strlen(searchw);

while (1)
{
pold = our_strcasestr(pold, searchw);
if (!pold)
break;
cleaned = 1;
startw = pold;
if (pold > line)
{
while (isalnum(*startw) && (startw != line))
startw--;
if (!isalnum(*startw))
startw++;
}

if (!(adword->type & WT_FAST_L) && (pold != startw))
{
pold++;
continue;
}

for (endw = pold; ((*endw != '\0') && (isalnum(*endw))); endw++);

if (!(adword->type & WT_FAST_R) && (pold+searchn != endw))
{
pold++;
continue;
}

if (poldx != startw)
{
int tmp_n = startw - poldx;
if (pnew + tmp_n >= c_eol)
{
memcpy(pnew, poldx, c_eol - pnew);
*c_eol = '\0';
return 1;
}

memcpy(pnew, poldx, tmp_n);
pnew += tmp_n;
}

if (replacen)
{
if ((pnew + replacen) >= c_eol) {
memcpy(pnew, replacew, c_eol - pnew);
*c_eol = '\0';
return 1;
}
memcpy(pnew, replacew, replacen);
pnew += replacen;
}
poldx = pold = endw;
}

if (*poldx)
{
strncpy(pnew, poldx, c_eol - pnew);
*c_eol = '\0';
}
else
*pnew = '\0';

return cleaned;
}

/*
* adword_checkmsg
* ===============
*
* The badword checking stuff was copied from src/badwords.c,
* I modified it a lot.
*/

#define SendNotice_channel \
sendto_channel_butone(&me, &me, chptr, \
":Uyari PRIVMSG %s :[\2Reklam\2] (%s Kanali Uyarisidir.! : \2%s\2 Adli Kullanici %s %s): \2%s\2 Kanal/Ozel 'de : \2%s\2 Yasaklanmis Kelimesini Kullandi.!", \
me.name, chptr->chname, from->name, \
cmd, to ? ":" : "", to ? to : "", str)

#define SendNotice_private \
sendto_serv_butone_token(NULL, me.name, MSG_GLOBOPS, TOK_GLOBOPS, \
"[\2Reklam\2] (%s Kanali Uyarisidir.! : \2%s\2 Adli Kullanici %s %s ): \2%s\2 Kanal/Ozel 'de : \2%s\2 Yasaklanmis Kelimesini Kullandi.!", \
from->name, cmd, \
to ? ":" : "", to ? to : "", str); \
sendto_failops_whoare_opers( \
"[\2Reklam\2] (%s Kanali Uyarisidir.! : \2%s\2 Adli Kullanici %s %s): \2%s\2 Kanal/Ozel 'de : \2%s\2 Yasaklanmis Kelimesini Kullandi.!", \
from->name, cmd, \
to ? ":" : "", to ? to : "", str)

static char *adword_checkmsg(aClient *cptr, aClient *from, char *to, char *str, u_int cmdtype, Adword *wordlist)
{
static regmatch_t pmatch[10];
static char cleanstr[4096], buf[4096];
char *ptr, *ptr2, *backref;
int matchlen = 0, stringlen, cleaned = 0;
u_int notify = 0, warn = 0, kill = 0;
u_int block = 0, ban = 0, ctcp, i;
ChanList *channels = NULL, *ch;
Adword *a;
ListStruct *next;

if (!myconf.enable_adwords || !wordlist)
return str;
if (!MyConnect(from) || !IsPerson(from) || IsAnOper(from))
return str;

stringlen = strlcpy(cleanstr, StripControlCodes(str), sizeof cleanstr);

/* Check for adwords */

for (a = wordlist; a; a = a->next)
{
/* 1. Some conditions before matching */

if (a->usertype == UT_REG && !IsRegNick(from))
continue;
if (a->usertype == UT_NONREG && IsRegNick(from))
continue;
if (cmdtype == CT_PRIVMSG || cmdtype == CT_NOTICE)
{
if (a->msgtype == MT_NOTICE && cmdtype != CT_NOTICE)
continue;
if (a->msgtype == MT_PRIVMSG && cmdtype == CT_NOTICE)
continue;
ctcp = (*str == '\001' && str[strlen(str)-1] == '\001');
if (a->msgtype == MT_CTCP && !ctcp)
continue;
if (a->msgtype == MT_NONCTCP && ctcp)
continue;
}

/* 2. Now try to match this word */

if (a->type & WT_REGEX)
{
if (regexec(a->expr, cleanstr, 0, NULL, 0))
continue;
}
else
{
if (!my_fast_badword_match(a, cleanstr))
continue;
}

/* 3. Check certain things if matched */

notify |= a->notify;
warn |= a->warn;
kill |= a->kill;
ban |= a->ban;
block |= a->block;

if (myconf.enable_notifications &&
(myconf.n_method == NM_CHANNEL) && notify && a->channel)
{
ch = (ChanList *) MyMallocEx(sizeof(ChanList));
ch->channel = a->channel;
AddListItem(ch, channels);
}

/* 4. Do the replaces if needed */

if (a->replace && !block)
{
buf[0] = 0;

if (a->type & WT_REGEX)
{
ptr = cleanstr;

if (!find_backref(a->replace))
{
while (!regexec(a->expr, ptr, 1, pmatch, 0))
{
if (pmatch[0].rm_so == -1)
break;
cleaned = 1;
matchlen += pmatch[0].rm_eo - pmatch[0].rm_so;
strlncat(buf, ptr, sizeof buf, pmatch[0].rm_so);
strlcat(buf, a->replace, sizeof buf);
ptr += pmatch[0].rm_eo;
}
}
else
{
while (!regexec(a->expr, ptr, 10, pmatch, 0))
{
if (pmatch[0].rm_so == -1)
break;

cleaned = 1;
matchlen += pmatch[0].rm_eo - pmatch[0].rm_so;
strlncat(buf, ptr, sizeof buf, pmatch[0].rm_so);
ptr2 = a->replace;

for (backref = find_backref(ptr2); backref; backref = find_backref(ptr2))
{
i = backref[1] - '0';
strlncat(buf, ptr2, sizeof buf, backref - ptr2);
if (pmatch[i].rm_so != -1)
strlncat(buf, ptr + pmatch[i].rm_so, sizeof buf,
pmatch[i].rm_eo - pmatch[i].rm_so);
ptr2 = backref + 2;
}

strlcat(buf, ptr2, sizeof buf);
ptr += pmatch[0].rm_eo;
}
}

strlcat(buf, ptr, sizeof buf);
strcpy(cleanstr, buf);
if (matchlen == stringlen)
break;
}
else
{
cleaned |= my_fast_badword_replace(a, cleanstr, buf, 512);
strcpy(cleanstr, buf);
}
}

/* 5. Post-checkings */

if (a->stoponmatch)
break;
}

/* Do other actions */

if (myconf.enable_notifications && notify)
{
char *cmd = find_CmdType(cmdtype);

if (myconf.n_method == NM_CHANNEL)
{
char *tmp, *name, *p = NULL;
aChannel *chptr;

if (myconf.channels)
{
tmp = strdup(myconf.channels);

for (name = strtoken(&p, tmp, ","); name; name = strtoken(&p, NULL, ","))
if ((chptr = find_channel(name, NullChn)) != NullChn)
SendNotice_channel;

MyFree(tmp);
}

for (ch = channels; ch; ch = (ChanList *) next)
{
next = (ListStruct *) ch->next;

if ((chptr = find_channel(ch->channel, NullChn)) != NullChn)
SendNotice_channel;

DelListItem(ch, channels);
MyFree(ch);
}
}
else
{
SendNotice_private;
}
}

if (myconf.enable_bans && ban)
{
#ifndef NO_PLACE_HOST_BAN
place_host_ban(from, myconf.ban_type,
myconf.ban_reason ? myconf.ban_reason
: DEF_BAN_REASON,
myconf.ban_period);
#else
char *bantype;

if ((bantype = find_BanFlag(myconf.ban_type)))
ban_client(from, bantype, myconf.ban_period,
myconf.ban_reason ? myconf.ban_reason
: DEF_BAN_REASON);
#endif
}
else if ((cmdtype != CT_QUIT) && myconf.enable_kills && kill)
{
/*
* Can't find a better solution for killing a user due to an adword;
* using the Event system seems to be working. The problem actually
* is we shouldn't kill a user more than one time (fe. when ppl use
* multiple targets in a PRIVMSG/NOTICE).
*/
strcpy(nickbuf, from->name);
EventAdd("adwords_kill", 0, 1, &adwords_event_kill, nickbuf);
}
else if (myconf.enable_warnings && warn)
{
if (myconf.enable_blockings && block)
sendto_one(from, ":%s NOTICE %s :%s",
me.name, from->name, myconf.block_message ?
myconf.block_message : DEF_BLOCK_MSG);
else
sendto_one(from, ":%s NOTICE %s :%s",
me.name, from->name, myconf.warning_message ?
myconf.warning_message : DEF_WARNING_MSG);
}

cleanstr[511] = '\0'; /* cutoff, just to be sure */

return (myconf.enable_blockings && block) ?
NULL : cleaned ? cleanstr : str;
}


/*
* cb_privmsg
* ==========
*
* from: who is sending the message
* to: who will receive it
* str: message text
* notice: tells whether it's a notice or privmsg
*/

static char *cb_privmsg(aClient *cptr, aClient *from, aClient *to, char *str, int notice)
{
if (!IsClient(from) || IsULine(from) || IsULine(to)
|| (myconf.require_mode_g && !IsFilteringWords(to)))
return str;

return adword_checkmsg(cptr, from, to->name, str,
notice ? CT_NOTICE : CT_PRIVMSG, AdwordsMessage);
}

/*
* cb_chanmsg
* ==========
*
* from: who is sending the message
* to: the channel where it will be sent to
* str: message text
* notice: tells whether it's a notice or privmsg
*/

static char *cb_chanmsg(aClient *cptr, aClient *from, aChannel *to, char *str, int notice)
{
ConfigItem_except *e;

if (!IsClient(from) || IsULine(from) || (myconf.require_mode_g
&& !(to->mode.mode & UMODE_STRIPBADWORDS)))
return str;

for (e = conf_exceptchan; e; e = (ConfigItem_except *) e->next)
if (!match(e->mask, to->chname))
return str;

return adword_checkmsg(cptr, from, to->chname, str,
notice? CT_NOTICE : CT_PRIVMSG, AdwordsChannel);
}

/*
* cb_quit
* =======
*
* sptr: who is sending the message
* comment: message text
*/

static char *cb_quit(aClient *sptr, char *comment)
{
Membership *lp;

if (IsULine(sptr))
return comment;

if (myconf.require_mode_g)
{
u_int strip = 0;

for (lp = sptr->user->channel; lp; lp = lp->next)
if (lp->chptr->mode.mode & UMODE_STRIPBADWORDS)
{
strip = 1;
break;
}

if (!strip)
return comment;
}

return adword_checkmsg(sptr, sptr, NULL, comment,
CT_QUIT, AdwordsQuit);
}

#ifndef HOOKTYPE_PRE_LOCAL_QUIT
/* ugly */
int override_quit(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[])
{
char *ocomment = (parc > 1 && parv[1]) ? parv[1] : parv[0];
static char comment[TOPICLEN + 1];
Membership *lp;

if (!IsServer(cptr) && IsPerson(sptr))
{
#ifdef STRIPBADWORDS
int blocked = 0;
#endif
char *s = comment;
if (STATIC_QUIT)
{
return exit_client(cptr, sptr, sptr, STATIC_QUIT);
}
if (!prefix_quit || strcmp(prefix_quit, "no"))
s = ircsprintf(comment, "%s ",
BadPtr(prefix_quit) ? "Quit:" : prefix_quit);
#ifdef STRIPBADWORDS
ocomment = (char *)stripbadwords_quit(ocomment, &blocked);
if (blocked)
ocomment = parv[0];
#endif
ocomment = cb_quit(sptr, ocomment);
if (!ocomment)
ocomment = parv[0];
if (!IsAnOper(sptr) && ANTI_SPAM_QUIT_MSG_TIME)
if (sptr->firsttime+ANTI_SPAM_QUIT_MSG_TIME > TStime())
ocomment = parv[0];

/* Strip color codes if any channel is +S, use nick as reason if +c. */
if (IsPerson(sptr) && (strchr(ocomment, '\003')))
{
unsigned char filtertype = 0; /* 1=filter, 2=block, highest wins. */
for (lp = sptr->user->channel; lp; lp = lp->next)
{
if (lp->chptr->mode.mode & MODE_NOCOLOR)
{
filtertype = 2;
break;
}
if (lp->chptr->mode.mode & MODE_STRIP)
{
if (!filtertype)
filtertype = 1;
}
}
if (filtertype == 1)
{
ocomment = StripColors(ocomment);
if (*ocomment == '\0')
ocomment = parv[0];
} else
if (filtertype == 2)
ocomment = parv[0];
} /* (strip color codes) */

strncpy(s, ocomment, TOPICLEN - (s - comment));
comment[TOPICLEN] = '\0';
return exit_client(cptr, sptr, sptr, comment);
}
else
{
return exit_client(cptr, sptr, sptr, ocomment);
}
}
#endif

#ifdef HOOKTYPE_PRE_LOCAL_PART
/*
* cb_partmsg
* ==========
*
* sptr: who is sending the message
* chptr: the channel where it will be sent to
* comment: message text
*/

static char *cb_partmsg(aClient *sptr, aChannel *chptr, char *comment)
{
ConfigItem_except *e;

if (!comment)
return NULL;
if (IsULine(sptr) || (myconf.require_mode_g && !(chptr->mode.mode & UMODE_STRIPBADWORDS)))
return comment;

for (e = conf_exceptchan; e; e = (ConfigItem_except *) e->next)
if (!match(e->mask, chptr->chname))
return comment;

return adword_checkmsg(sptr, sptr, chptr->chname, comment, CT_PART, AdwordsPart);
}
#endif


/*
* m_adwords
* =========
*
* parv[0]: sender prefix
* parv[1]: option
* parv[2]: value (optional)
*
*/

static int m_adwords(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
ConfigItem_except *e = NULL;

if (!MyConnect(sptr) || !IsPerson(sptr) || !IsAnOper(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (parc < 2 || BadPtr(parv[1]))
{
sendto_one(sptr, ":%s NOTICE %s :Usage:",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : /adwords <option>",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s :Options:",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : message: shows you the adword message block list",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : channel: shows you the adword channel block list",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : quit: shows you the adword quit block list",
me.name, sptr->name);
#ifdef HOOKTYPE_PRE_LOCAL_PART
sendto_one(sptr, ":%s NOTICE %s : part: shows you the adword part block list",
me.name, sptr->name);
#endif
sendto_one(sptr, ":%s NOTICE %s : all: shows you all the adword block list",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : exceptions: shows you the except channel mask list",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : config: displays adwords configuration",
me.name, sptr->name);
return 0;
}
if (!strcasecmp(parv[1], "message"))
{
stats_wordlist(sptr, AdwordsMessage, 'M');
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'a');
}
else if (!strcasecmp(parv[1], "channel"))
{
stats_wordlist(sptr, AdwordsChannel, 'C');
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'a');
}
else if (!strcasecmp(parv[1], "quit"))
{
stats_wordlist(sptr, AdwordsQuit, 'Q');
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'a');
}
#ifdef HOOKTYPE_PRE_LOCAL_PART
else if (!strcasecmp(parv[1], "part"))
{
stats_wordlist(sptr, AdwordsPart, 'P');
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'a');
}
#endif
else if (!strcasecmp(parv[1], "all"))
{
stats_wordlist(sptr, AdwordsMessage, 'M');
stats_wordlist(sptr, AdwordsChannel, 'C');
stats_wordlist(sptr, AdwordsQuit, 'Q');
#ifdef HOOKTYPE_PRE_LOCAL_PART
stats_wordlist(sptr, AdwordsPart, 'P');
#endif
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'a');
}
else if (!strcasecmp(parv[1], "exceptions"))
{
for (e = conf_exceptchan; e; e = (ConfigItem_except *) e->next)
sendto_one(sptr, ":%s %i %s :m %s",
me.name, RPL_TEXT, sptr->name, e->mask);
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'm');
}
else if (!strcasecmp(parv[1], "config"))
cb_stats(sptr);
else
{
sendto_one(sptr, ":%s NOTICE %s :Unknown option %s."
" Valid options are: message | channel | all | exceptions | config",
me.name, sptr->name, parv[1]);
return -1;
}

return 0;
}

static void stats_wordlist(aClient *sptr, Adword *wordlist, char wtype)
{
Adword *a;

for (a = wordlist; a; a = (Adword *) a->next)
sendto_one(sptr, ":%s %i %s :a %c %c %c %c %s %s%s%s" "%s%s" "%s%s",
me.name, RPL_TEXT, sptr->name,
wtype,
find_WordFlag(a->type),
find_MsgType(a->msgtype),
find_UserType(a->usertype),
make_optlist(a),
a->type & WT_FAST_L ? "*" : "",
a->word,
a->type & WT_FAST_R ? "*" : "",
a->replace ? " " : "",
a->replace ? a->replace : "",
a->channel ? " " : "",
a->channel ? a->channel : "");
}

static void adwords_event_kill(char *name)
{
aClient *cptr;

if ((cptr = find_person(name, NULL)))
exit_client(cptr, cptr, &me,
myconf.kill_reason ? myconf.kill_reason : DEF_KILL_REASON);
}

King_of_Night
05-10-2006, 20:13
/*
* IRC - Internet Relay Chat, antimoon.c
* (C) Copyright 2004, Bram Matthys (Syzop)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "proto.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef STRIPBADWORDS
#include "badwords.h"
#endif
#ifdef _WIN32
#include "version.h"
#endif

/* Configurable items: */
#define ANTIMOON_BANACT BAN_ACT_GZLINE
#define ANTIMOON_REASON "Infected with MyMoon virus"
#define ANTIMOON_BANTIME 86400
/* End of configurable items */

ModuleHeader MOD_HEADER(antimoon)
= {
"antimoon",
"v0.2",
"MyMoon trojan detector by Syzop",
"3.2-b8-1",
NULL
};

static char *nameslist[] = {
"adams",
"allen",
"allison",
"alvarez",
"andrson",
"andrews",
"armsong",
"arnold",
"avila",
"bailey",
"baker",
"barnes",
"bennett",
"bishop",
"boyd",
"bradley",
"brooks",
"brown",
"bryan",
"burke",
"burton",
"butler",
"campbell",
"carlson",
"carr",
"carter",
"chase",
"chen",
"christ",
"clark",
"collins",
"comer",
"cook",
"cooper",
"cox",
"crawford",
"cunnin",
"davis",
"day",
"dean",
"dickins",
"edwards",
"elliott",
"ellis",
"evans",
"fischer",
"fisher",
"fong",
"ford",
"freeman",
"frost",
"garcia",
"gardner",
"gomes",
"gomez",
"gonzales",
"graham",
"green",
"griffin",
"mymoon",
"Fight",
"Fool",
"Makar",
"Foremos",
"Frien",
"Gargar",
"Gere",
"Grai",
"Grant",
"Grenic",
"Guneu",
"Gygae",
"Gyrti",
"Gyrto",
"Haem",
"Herm",
"Her",
"Hono",
"Honour",
"Hours",
"Hyads",
"Hyperik",
"Hyperk",
"Hypse",
"Hyppyle",
"Hyria",
"Hyrmine",
"Hyrtacus",
"Hyrtius",
"Iaera",
"Ialmenus",
"Iamenus",
"Ianassa",
"Ianeira",
"Iapetus",
"Iardanus",
"Iasus",
"Icarian",
"Idaeus",
"Ides",
"Idomens",
"Ielysus",
"Ilioneus",
"Ilithuia",
"Ilithui",
"Ilius",
"Ilus",
"Imbras",
"Imbrius",
"Imbros",
"Imbrus",
"Insolen",
"Laodame",
"Leonte",
"Lesbia",
"Lesbos",
"Lethus",
"Leto",
"Leucus",
"Lycian",
"Lycians",
"Lycomed",
"Lycon",
"Lycophon",
"Lycoph",
"Lyctus",
"Lycur",
"Maera",
"Magnetes",
"Mantinea",
"Maris",
"Marpsa",
"Mases",
"Mastor",
"Melappus",
"Manthus",
"Menheus",
"Menehius",
"Menoius",
"Menon",
"Mentes",
"Mydon",
"Mygdon",
"Mynes",
"Myrine",
"Myrm",
NULL
};

DLLFUNC int antimoon_useroverride(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);

ModuleInfo AntiMoon;

DLLFUNC int MOD_INIT(antimoon)(ModuleInfo *modinfo)
{
bcopy(modinfo, &AntiMoon,modinfo->size);
return MOD_SUCCESS;
}

DLLFUNC int MOD_LOAD(antimoon)(int module_load)
{
CmdoverrideAdd(AntiMoon.handle, "USER", antimoon_useroverride);
return MOD_SUCCESS;
}

DLLFUNC int MOD_UNLOAD(antimoon)(int module_unload)
{
return MOD_SUCCESS;
}

static int is_in_nameslist(char *name)
{
char **s;
for (s=nameslist; *s; *s++)
{
if (!strcmp(name, *s))
return 1;
}
return 0;
}

/* USER <name> 0 * :<name><digits> */
DLLFUNC int antimoon_useroverride(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[])
{
if (MyConnect(sptr) && !IsServer(sptr) && (parc > 4) &&
!strcmp(parv[2], "0") && !strcmp(parv[3], "*") && (sptr->name[0] == '\0'))
{
char **s, match=0;
/* Check if <name> is present in 1st parameter... */
if (is_in_nameslist(parv[1]))
{
/* It was, now check for <name><digits> in realname */
char buf[32], *p;
strlcpy(buf, parv[4], sizeof(buf));
for (p=buf; *p; p++)
if (isdigit(*p))
{
match++;
*p = '\0';
break;
}
if (match && is_in_nameslist(buf)) /* stuff before digits also matched a name? */
{
return place_host_ban(sptr, ANTIMOON_BANACT, ANTIMOON_REASON, ANTIMOON_BANTIME);
}
}
}

if (ovr->prev)
return ovr->prev->func(ovr->prev, cptr, sptr, parc, parv);
else
return ovr->command->func(cptr, sptr, parc, parv);
}

King_of_Night
05-10-2006, 20:14
/*
* IRC - Internet Relay Chat, antirandom.c
* (C) Copyright 2004-2005, Bram Matthys (Syzop) <syzop@vulnscan.org>
*
* Contains ideas from Keith Dunnett <keith@dunnett.org>
* Most of the detection mechanisms come from SpamAssassin FVGT_Tripwire.
*
* $Id: antirandom.c,v 1.21 2005/07/22 01:04:38 syzop Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "proto.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef STRIPBADWORDS
#include "badwords.h"
#endif
#ifdef _WIN32
#include "version.h"
#endif

/**** NOTE: CONFIGURATION HAS MOVED TO THE UNREALIRCD.CONF, SEE README
**** FOR MORE DETAILS.
****/



/* You can change this 'undef' into 'define' if you want to see quite
* a flood for every user that connects (and on-load if cfg.fullstatus_on_load).
* Obviously only recommended for testing, use with care!
*/
#undef DEBUGMODE

/** Change this 'undef' to 'define' to get performance information.
* This really only meant for debugging purposes.
*/
#undef TIMING

ModuleHeader MOD_HEADER(antirandom)
= {
"antirandom",
"v1.1",
"Randomness detector",
"3.2-b8-1",
NULL
};

#ifndef MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#endif

#ifndef _WIN32
typedef struct {
char *regex;
int score;
} ScoreTable;
#endif

typedef struct _dynlist DynList;
struct _dynlist {
DynList *prev, *next;
char *entry;
};

#ifndef _WIN32
/* You can define regexes here.. the format is:
* {"<REGEX>", SCORE},
*/
ScoreTable regex_scores[] = {
/* These have all been moved to internal digit/vowel/consonant checks.
* But I've left the regex ability here, in case someone else uses it.
*/
{NULL, 0}
};
#endif

/* "<char1><char2>" followed by "<rest>" */
static char *triples_txt[] = {
"aj", "fqtvxz",
"aq", "deghjkmnprtxyz",
"av", "bfhjqwxz",
"az", "jwx",
"bd", "bghjkmpqvxz",
"bf", "bcfgjknpqvwxyz",
"bg", "bdfghjkmnqstvxz",
"bh", "bfhjkmnqvwxz",
"bj", "bcdfghjklmpqtvwxyz",
"bk", "dfjkmqrvwxyz",
"bl", "bgpqwxz",
"bm", "bcdflmnqz",
"bn", "bghjlmnpqtvwx",
"bp", "bfgjknqvxz",
"bq", "bcdefghijklmnopqrstvwxyz",
"bt", "dgjkpqtxz",
"bv", "bfghjklnpqsuvwxz",
"bw", "bdfjknpqsuwxyz",
"bx", "abcdfghijklmnopqtuvwxyz",
"bz", "bcdfgjklmnpqrstvwxz",
"cb", "bfghjkpqyz",
"cc", "gjqxz",
"cd", "hjkqvwxz",
"cf", "gjknqvwyz",
"cg", "bdfgjkpqvz",
"cl", "fghjmpqxz",
"cm", "bjkqv",
"cn", "bghjkpqwxz",
"cp", "gjkvxyz",
"cq", "abcdefghijklmnopqsvwxyz",
"cr", "gjqx",
"cs", "gjxz",
"cv", "bdfghjklmnquvwxyz",
"cx", "abdefghjklmnpqrstuvwxyz",
"cy", "jqy",
"cz", "bcdfghjlpqrtvwxz",
"db", "bdgjnpqtxz",
"dc", "gjqxz",
"dd", "gqz",
"df", "bghjknpqvxyz",
"dg", "bfgjqvxz",
"dh", "bfkmnqwxz",
"dj", "bdfghjklnpqrwxz",
"dk", "cdhjkpqrtuvwxz",
"dl", "bfhjknqwxz",
"dm", "bfjnqw",
"dn", "fgjkmnpqvwz",
"dp", "bgjkqvxz",
"dq", "abcefghijkmnopqtvwxyz",
"dr", "bfkqtvx",
"dt", "qtxz",
"dv", "bfghjknqruvwyz",
"dw", "cdfjkmnpqsvwxz",
"dx", "abcdeghjklmnopqrsuvwxyz",
"dy", "jyz",
"dz", "bcdfgjlnpqrstvxz",
"eb", "jqx",
"eg", "cjvxz",
"eh", "hxz",
"ej", "fghjpqtwxyz",
"ek", "jqxz",
"ep", "jvx",
"eq", "bcghijkmotvxyz",
"ev", "bfpq",
"fc", "bdjkmnqvxz",
"fd", "bgjklqsvyz",
"fg", "fgjkmpqtvwxyz",
"fh", "bcfghjkpqvwxz",
"fj", "bcdfghijklmnpqrstvwxyz",
"fk", "bcdfghjkmpqrstvwxz",
"fl", "fjkpqxz",
"fm", "dfhjlmvwxyz",
"fn", "bdfghjklnqrstvwxz",
"fp", "bfjknqtvwxz",
"fq", "abcefghijklmnopqrstvwxyz",
"fr", "nqxz",
"fs", "gjxz",
"ft", "jqx",
"fv", "bcdfhjklmnpqtuvwxyz",
"fw", "bcfgjklmpqstuvwxyz",
"fx", "bcdfghjklmnpqrstvwxyz",
"fy", "ghjpquvxy",
"fz", "abcdfghjklmnpqrtuvwxyz",
"gb", "bcdknpqvwx",
"gc", "gjknpqwxz",
"gd", "cdfghjklmqtvwxz",
"gf", "bfghjkmnpqsvwxyz",
"gg", "jkqvxz",
"gj", "bcdfghjklmnpqrstvwxyz",
"gk", "bcdfgjkmpqtvwxyz",
"gl", "fgjklnpqwxz",
"gm", "dfjkmnqvxz",
"gn", "jkqvxz",
"gp", "bjknpqtwxyz",
"gq", "abcdefghjklmnopqrsvwxyz",
"gr", "jkqt",
"gt", "fjknqvx",
"gu", "qwx",
"gv", "bcdfghjklmpqstvwxyz",
"gw", "bcdfgjknpqtvwxz",
"gx", "abcdefghjklmnopqrstvwxyz",
"gy", "jkqxy",
"gz", "bcdfgjklmnopqrstvxyz",
"hb", "bcdfghjkqstvwxz",
"hc", "cjknqvwxz",
"hd", "fgjnpvz",
"hf", "bfghjkmnpqtvwxyz",
"hg", "bcdfgjknpqsxyz",
"hh", "bcgklmpqrtvwxz",
"hj", "bcdfgjkmpqtvwxyz",
"hk", "bcdgkmpqrstvwxz",
"hl", "jxz",
"hm", "dhjqrvwxz",
"hn", "jrxz",
"hp", "bjkmqvwxyz",
"hq", "abcdefghijklmnopqrstvwyz",
"hr", "cjqx",
"hs", "jqxz",
"hv", "bcdfgjklmnpqstuvwxz",
"hw", "bcfgjklnpqsvwxz",
"hx", "abcdefghijklmnopqrstuvwxyz",
"hz", "bcdfghjklmnpqrstuvwxz",
"ib", "jqx",
"if", "jqvwz",
"ih", "bgjqx",
"ii", "bjqxy",
"ij", "cfgqxy",
"ik", "bcfqx",
"iq", "cdefgjkmnopqtvxyz",
"iu", "hiwxy",
"iv", "cfgmqx",
"iw", "dgjkmnpqtvxz",
"ix", "jkqrxz",
"iy", "bcdfghjklpqtvwx",
"jb", "bcdghjklmnopqrtuvwxyz",
"jc", "cfgjkmnopqvwxy",
"jd", "cdfghjlmnpqrtvwx",
"jf", "abcdfghjlnopqrtuvwxyz",
"jg", "bcdfghijklmnopqstuvwxyz",
"jh", "bcdfghjklmnpqrxyz",
"jj", "bcdfghjklmnopqrstuvwxyz",
"jk", "bcdfghjknqrtwxyz",
"jl", "bcfghjmnpqrstuvwxyz",
"jm", "bcdfghiklmnqrtuvwyz",
"jn", "bcfjlmnpqsuvwxz",
"jp", "bcdfhijkmpqstvwxyz",
"jq", "abcdefghijklmnopqrstuvwxyz",
"jr", "bdfhjklpqrstuvwxyz",
"js", "bfgjmoqvxyz",
"jt", "bcdfghjlnpqrtvwxz",
"jv", "abcdfghijklpqrstvwxyz",
"jw", "bcdefghijklmpqrstuwxyz",
"jx", "abcdefghijklmnopqrstuvwxyz",
"jy", "bcdefghjkpqtuvwxyz",
"jz", "bcdfghijklmnopqrstuvwxyz",
"kb", "bcdfghjkmqvwxz",
"kc", "cdfgjknpqtwxz",
"kd", "bfghjklmnpqsvwxyz",
"kf", "bdfghjkmnpqsvwxyz",
"kg", "cghjkmnqtvwxyz",
"kh", "cfghjkqx",
"kj", "bcdfghjkmnpqrstwxyz",
"kk", "bcdfgjmpqswxz",
"kl", "cfghlmqstwxz",
"km", "bdfghjknqrstwxyz",
"kn", "bcdfhjklmnqsvwxz",
"kp", "bdfgjkmpqvxyz",
"kq", "abdefghijklmnopqrstvwxyz",
"kr", "bcdfghjmqrvwx",
"ks", "jqx",
"kt", "cdfjklqvx",
"ku", "qux",
"kv", "bcfghjklnpqrstvxyz",
"kw", "bcdfgjklmnpqsvwxz",
"kx", "abcdefghjklmnopqrstuvwxyz",
"ky", "vxy",
"kz", "bcdefghjklmnpqrstuvwxyz",
"lb", "cdgkqtvxz",
"lc", "bqx",
"lg", "cdfgpqvxz",
"lh", "cfghkmnpqrtvx",
"lk", "qxz",
"ln", "cfjqxz",
"lp", "jkqxz",
"lq", "bcdefhijklmopqrstvwxyz",
"lr", "dfgjklmpqrtvwx",
"lv", "bcfhjklmpwxz",
"lw", "bcdfgjknqxz",
"lx", "bcdfghjklmnpqrtuwz",
"lz", "cdjptvxz",
"mb", "qxz",
"md", "hjkpvz",
"mf", "fkpqvwxz",
"mg", "cfgjnpqsvwxz",
"mh", "bchjkmnqvx",
"mj", "bcdfghjknpqrstvwxyz",
"mk", "bcfgklmnpqrvwxz",
"ml", "jkqz",
"mm", "qvz",
"mn", "fhjkqxz",
"mq", "bdefhjklmnopqtwxyz",
"mr", "jklqvwz",
"mt", "jkq",
"mv", "bcfghjklmnqtvwxz",
"mw", "bcdfgjklnpqsuvwxyz",
"mx", "abcefghijklmnopqrstvwxyz",
"mz", "bcdfghjkmnpqrstvwxz",
"nb", "hkmnqxz",
"nf", "bghqvxz",
"nh", "fhjkmqtvxz",
"nk", "qxz",
"nl", "bghjknqvwxz",
"nm", "dfghjkqtvwxz",
"np", "bdjmqwxz",
"nq", "abcdfghjklmnopqrtvwxyz",
"nr", "bfjkqstvx",
"nv", "bcdfgjkmnqswxz",
"nw", "dgjpqvxz",
"nx", "abfghjknopuyz",
"nz", "cfqrxz",
"oc", "fjvw",
"og", "qxz",
"oh", "fqxz",
"oj", "bfhjmqrswxyz",
"ok", "qxz",
"oq", "bcdefghijklmnopqrstvwxyz",
"ov", "bfhjqwx",
"oy", "qxy",
"oz", "fjpqtvx",
"pb", "fghjknpqvwz",
"pc", "gjq",
"pd", "bgjkvwxz",
"pf", "hjkmqtvwyz",
"pg", "bdfghjkmqsvwxyz",
"ph", "kqvx",
"pk", "bcdfhjklmpqrvx",
"pl", "ghkqvwx",
"pm", "bfhjlmnqvwyz",
"pn", "fjklmnqrtvwz",
"pp", "gqwxz",
"pq", "abcdefghijklmnopqstvwxyz",
"pr", "hjkqrwx",
"pt", "jqxz",
"pv", "bdfghjklquvwxyz",
"pw", "fjkmnpqsuvwxz",
"px", "abcdefghijklmnopqrstuvwxyz",
"pz", "bdefghjklmnpqrstuvwxyz",
"qa", "ceghkopqxy",
"qb", "bcdfghjklmnqrstuvwxyz",
"qc", "abcdfghijklmnopqrstuvwxyz",
"qd", "defghijklmpqrstuvwxyz",
"qe", "abceghjkmopquwxyz",
"qf", "abdfghijklmnopqrstuvwxyz",
"qg", "abcdefghijklmnopqrtuvwxz",
"qh", "abcdefghijklmnopqrstuvwxyz",
"qi", "efgijkmpwx",
"qj", "abcdefghijklmnopqrstuvwxyz",
"qk", "abcdfghijklmnopqrsuvwxyz",
"ql", "abcefghjklmnopqrtuvwxyz",
"qm", "bdehijklmnoqrtuvxyz",
"qn", "bcdefghijklmnoqrtuvwxyz",
"qo", "abcdefgijkloqstuvwxyz",
"qp", "abcdefghijkmnopqrsuvwxyz",
"qq", "bcdefghijklmnopstwxyz",
"qr", "bdefghijklmnoqruvwxyz",
"qs", "bcdefgijknqruvwxz",
"qt", "befghjklmnpqtuvwxz",
"qu", "cfgjkpwz",
"qv", "abdefghjklmnopqrtuvwxyz",
"qw", "bcdfghijkmnopqrstuvwxyz",
"qx", "abcdefghijklmnopqrstuvwxyz",
"qy", "abcdefghjklmnopqrstuvwxyz",
"qz", "abcdefghijklmnopqrstuvwxyz",
"rb", "fxz",
"rg", "jvxz",
"rh", "hjkqrxz",
"rj", "bdfghjklmpqrstvwxz",
"rk", "qxz",
"rl", "jnq",
"rp", "jxz",
"rq", "bcdefghijklmnopqrtvwxy",
"rr", "jpqxz",
"rv", "bcdfghjmpqrvwxz",
"rw", "bfgjklqsvxz",
"rx", "bcdfgjkmnopqrtuvwxz",
"rz", "djpqvxz",
"sb", "kpqtvxz",
"sd", "jqxz",
"sf", "bghjkpqw",
"sg", "cgjkqvwxz",
"sj", "bfghjkmnpqrstvwxz",
"sk", "qxz",
"sl", "gjkqwxz",
"sm", "fkqwxz",
"sn", "dhjknqvwxz",
"sq", "bfghjkmopstvwxz",
"sr", "jklqrwxz",
"sv", "bfhjklmnqtwxyz",
"sw", "jkpqvwxz",
"sx", "bcdefghjklmnopqrtuvwxyz",
"sy", "qxy",
"sz", "bdfgjpqsvxz",
"tb", "cghjkmnpqtvwx",
"tc", "jnqvx",
"td", "bfgjkpqtvxz",
"tf", "ghjkqvwyz",
"tg", "bdfghjkmpqsx",
"tj", "bdfhjklmnpqstvwxyz",
"tk", "bcdfghjklmpqvwxz",
"tl", "jkqwxz",
"tm", "bknqtwxz",
"tn", "fhjkmqvwxz",
"tp", "bjpqvwxz",
"tq", "abdefhijklmnopqrstvwxyz",
"tr", "gjqvx",
"tv", "bcfghjknpquvwxz",
"tw", "bcdfjknqvz",
"tx", "bcdefghjklmnopqrsuvwxz",
"tz", "jqxz",
"uc", "fjmvx",
"uf", "jpqvx",
"ug", "qvx",
"uh", "bcgjkpvxz",
"uj", "wbfghklmqvwx",
"uk", "fgqxz",
"uq", "bcdfghijklmnopqrtwxyz",
"uu", "fijkqvwyz",
"uv", "bcdfghjkmpqtwxz",
"uw", "dgjnquvxyz",
"ux", "jqxz",
"uy", "jqxyz",
"uz", "fgkpqrx",
"vb", "bcdfhijklmpqrtuvxyz",
"vc", "bgjklnpqtvwxyz",
"vd", "bdghjklnqvwxyz",
"vf", "bfghijklmnpqtuvxz",
"vg", "bcdgjkmnpqtuvwxyz",
"vh", "bcghijklmnpqrtuvwxyz",
"vj", "abcdfghijklmnpqrstuvwxyz",
"vk", "bcdefgjklmnpqruvwxyz",
"vl", "hjkmpqrvwxz",
"vm", "bfghjknpquvxyz",
"vn", "bdhjkmnpqrtuvwxz",
"vp", "bcdeghjkmopqtuvwyz",
"vq", "abcdefghijklmnopqrstvwxyz",
"vr", "fghjknqrtvwxz",
"vs", "dfgjmqz",
"vt", "bdfgjklmnqtx",
"vu", "afhjquwxy",
"vv", "cdfghjkmnpqrtuwxz",
"vw", "abcdefghijklmnopqrtuvwxyz",
"vx", "abcefghjklmnopqrstuvxyz",
"vy", "oqx",
"vz", "abcdefgjklmpqrstvwxyz",
"wb", "bdfghjpqtvxz",
"wc", "bdfgjkmnqvwx",
"wd", "dfjpqvxz",
"wf", "cdghjkmqvwxyz",
"wg", "bcdfgjknpqtvwxyz",
"wh", "cdghjklpqvwxz",
"wj", "bfghijklmnpqrstvwxyz",
"wk", "cdfgjkpqtuvxz",
"wl", "jqvxz",
"wm", "dghjlnqtvwxz",
"wp", "dfgjkpqtvwxz",
"wq", "abcdefghijklmnopqrstvwxyz",
"wr", "cfghjlmpqwx",
"wt", "bdgjlmnpqtvx",
"wu", "aikoquvwy",
"wv", "bcdfghjklmnpqrtuvwxyz",
"ww", "bcdgkpqstuvxyz",
"wx", "abcdefghijklmnopqrstuvwxz",
"wy", "jquwxy",
"wz", "bcdfghjkmnopqrstuvwxz",
"xa", "ajoqy",
"xb", "bcdfghjkmnpqsvwxz",
"xc", "bcdgjkmnqsvwxz",
"xd", "bcdfghjklnpqstuvwxyz",
"xf", "bcdfghjkmnpqtvwxyz",
"xg", "bcdfghjkmnpqstvwxyz",
"xh", "cdfghjkmnpqrstvwxz",
"xi", "jkqy",
"xj", "abcdefghijklmnopqrstvwxyz",
"xk", "abcdfghjkmnopqrstuvwxyz",
"xl", "bcdfghjklmnpqrvwxz",
"xm", "bcdfghjknpqvwxz",
"xn", "bcdfghjklmnpqrvwxyz",
"xp", "bcfjknpqvxz",
"xq", "abcdefghijklmnopqrstvwxyz",
"xr", "bcdfghjklnpqrsvwyz",
"xs", "bdfgjmnqrsvxz",
"xt", "jkpqvwxz",
"xu", "fhjkquwx",
"xv", "bcdefghjklmnpqrsuvwxyz",
"xw", "bcdfghjklmnpqrtuvwxyz",
"xx", "bcdefghjkmnpqrstuwyz",
"xy", "jxy",
"xz", "abcdefghjklmnpqrstuvwxyz",
"yb", "cfghjmpqtvwxz",
"yc", "bdfgjmpqsvwx",
"yd", "chjkpqvwx",
"yf", "bcdghjmnpqsvwx",
"yg", "cfjkpqtxz",
"yh", "bcdfghjkpqx",
"yi", "hjqwxy",
"yj", "bcdfghjklmnpqrstvwxyz",
"yk", "bcdfgpqvwxz",
"ym", "dfgjqvxz",
"yp", "bcdfgjkmqxz",
"yq", "abcdefghijklmnopqrstvwxyz",
"yr", "jqx",
"yt", "bcfgjnpqx",
"yv", "bcdfghjlmnpqstvwxz",
"yw", "bfgjklmnpqstuvwxz",
"yx", "bcdfghjknpqrstuvwxz",
"yy", "bcdfghjklpqrstvwxz",
"yz", "bcdfjklmnpqtvwx",
"zb", "dfgjklmnpqstvwxz",
"zc", "bcdfgjmnpqstvwxy",
"zd", "bcdfghjklmnpqstvwxy",
"zf", "bcdfghijkmnopqrstvwxyz",
"zg", "bcdfgjkmnpqtvwxyz",
"zh", "bcfghjlpqstvwxz",
"zj", "abcdfghjklmnpqrstuvwxyz",
"zk", "bcdfghjklmpqstvwxz",
"zl", "bcdfghjlnpqrstvwxz",
"zm", "bdfghjklmpqstvwxyz",
"zn", "bcdfghjlmnpqrstuvwxz",
"zp", "bcdfhjklmnpqstvwxz",
"zq", "abcdefghijklmnopqrstvwxyz",
"zr", "bcfghjklmnpqrstvwxyz",
"zs", "bdfgjmnqrsuwxyz",
"zt", "bcdfgjkmnpqtuvwxz",
"zu", "ajqx",
"zv", "bcdfghjklmnpqrstuvwxyz",
"zw", "bcdfghjklmnpqrstuvwxyz",
"zx", "abcdefghijklmnopqrstuvwxyz",
"zy", "fxy",
"zz", "cdfhjnpqrvx",
NULL, NULL
};

#ifndef _WIN32
/* Used for parsed sregexes */
typedef struct _regexlist RegexList;
struct _regexlist {
RegexList *next;
regex_t regex;
#ifdef DEBUGMODE
char *regextxt;
#endif
int score;
};
#endif

/* Used for parsed triples: */
#define TRIPLES_REST_SIZE 32
typedef struct _triples Triples;
struct _triples {
Triples *next;
char two[3];
char rest[TRIPLES_REST_SIZE];
};

#ifndef _WIN32
RegexList *sregexes = NULL;
#endif
Triples *triples = NULL;

struct {
int threshold;
int ban_action;
int ban_reason;
int ban_time;
} req;

struct {
int threshold;
int ban_action;
char *ban_reason;
long ban_time;
int show_failedconnects;
int fullstatus_on_load;
DynList *except_hosts;
} cfg;

/* Forward declarations */
static int init_stuff(void);
static int init_sregexes(void);
static int init_triples(void);
static void free_stuff(void);
static void free_config(void);
DLLFUNC int antirandom_config_test(ConfigFile *, ConfigEntry *, int, int *);
DLLFUNC int antirandom_config_run(ConfigFile *, ConfigEntry *, int);
DLLFUNC int antirandom_config_posttest(int *);
static int is_except_host(aClient *sptr);


DLLFUNC int antirandom_preconnect(aClient *sptr);

DLLFUNC int MOD_TEST(antirandom)(ModuleInfo *modinfo)
{
memset(&req, 0, sizeof(req));
memset(&cfg, 0, sizeof(cfg));
HookAddEx(modinfo->handle, HOOKTYPE_CONFIGTEST, antirandom_config_test);
HookAddEx(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, antirandom_config_posttest);
return MOD_SUCCESS;
}

DLLFUNC int MOD_INIT(antirandom)(ModuleInfo *modinfo)
{
if (!init_stuff())
{
config_error("antirandom: loading aborted");
free_stuff();
return MOD_FAILED;
}
cfg.fullstatus_on_load = 1; /* default */
HookAddEx(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, antirandom_preconnect);
HookAddEx(modinfo->handle, HOOKTYPE_CONFIGRUN, antirandom_config_run);

return MOD_SUCCESS;
}

void check_all_users(void);

DLLFUNC int MOD_LOAD(antirandom)(int module_load)
{
if (cfg.fullstatus_on_load)
check_all_users();
return MOD_SUCCESS;
}

DLLFUNC int MOD_UNLOAD(antirandom)(int module_unload)
{
free_stuff();
free_config();
return MOD_SUCCESS;
}

static void free_config(void)
{
DynList *d, *d_next;

if (cfg.ban_reason)
MyFree(cfg.ban_reason);
for (d=cfg.except_hosts; d; d=d_next)
{
d_next = d->next;
MyFree(d->entry);
MyFree(d);
}

memset(&cfg, 0, sizeof(cfg)); /* needed! */
}

DLLFUNC int antirandom_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
{
int errors = 0;
ConfigEntry *cep;

if (type != CONFIG_SET)
return 0;

/* We are only interrested in set::antirandom... */
if (!ce || !ce->ce_varname || strcmp(ce->ce_varname, "antirandom"))
return 0;

for (cep = ce->ce_entries; cep; cep = cep->ce_next)
{
if (!cep->ce_varname)
{
config_error("%s:%i: blank set::antirandom item",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
errors++;
} else
if (!strcmp(cep->ce_varname, "except-hosts"))
{
} else
if (!cep->ce_vardata)
{
config_error("%s:%i: set::antirandom::%s with no value",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
errors++;
} else
if (!strcmp(cep->ce_varname, "threshold"))
{
req.threshold = 1;
} else
if (!strcmp(cep->ce_varname, "ban-action"))
{
if (!banact_stringtoval(cep->ce_vardata))
{
config_error("%s:%i: set::antirandom::ban-action: unknown action '%s'",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
errors++;
} else
req.ban_action = 1;
} else
if (!strcmp(cep->ce_varname, "ban-reason"))
{
req.ban_reason = 1;
} else
if (!strcmp(cep->ce_varname, "ban-time"))
{
req.ban_time = 1;
} else
if (!strcmp(cep->ce_varname, "fullstatus-on-load"))
{
} else
if (!strcmp(cep->ce_varname, "show-failedconnects"))
{
} else
{
config_error("%s:%i: unknown directive set::antirandom::%s",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
errors++;
}
}
*errs = errors;
return errors ? -1 : 1;
}

DLLFUNC int antirandom_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
{
ConfigEntry *cep, *cep2;
DynList *d;

if (type != CONFIG_SET)
return 0;

/* We are only interrested in set::antirandom... */
if (!ce || !ce->ce_varname || strcmp(ce->ce_varname, "antirandom"))
return 0;

for (cep = ce->ce_entries; cep; cep = cep->ce_next)
{
if (!strcmp(cep->ce_varname, "except-hosts"))
{
for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
{
d = MyMallocEx(sizeof(DynList));
d->entry = strdup(cep2->ce_varname);
AddListItem(d, cfg.except_hosts);
}
} else
if (!strcmp(cep->ce_varname, "threshold"))
{
cfg.threshold = atoi(cep->ce_vardata);
} else
if (!strcmp(cep->ce_varname, "ban-action"))
{
cfg.ban_action = banact_stringtoval(cep->ce_vardata);
} else
if (!strcmp(cep->ce_varname, "ban-reason"))
{
if (cfg.ban_reason)
MyFree(cfg.ban_reason);
cfg.ban_reason = strdup(cep->ce_vardata);
} else
if (!strcmp(cep->ce_varname, "ban-time"))
{
cfg.ban_time = config_checkval(cep->ce_vardata, CFG_TIME);
} else
if (!strcmp(cep->ce_varname, "show-failedconnects"))
{
cfg.show_failedconnects = config_checkval(cep->ce_vardata, CFG_YESNO);
} else
if (!strcmp(cep->ce_varname, "fullstatus-on-load"))
{
cfg.fullstatus_on_load = config_checkval(cep->ce_vardata, CFG_YESNO);
}
}
return 1;
}

DLLFUNC int antirandom_config_posttest(int *errs)
{
int errors = 0;

if (!req.threshold) { config_error("set::antirandom::threshold missing"); errors++; }
if (!req.ban_action) { config_error("set::antirandom::ban-action missing"); errors++; }
if (!req.ban_time) { config_error("set::antirandom::ban-time missing"); errors++; }
if (!req.ban_reason) { config_error("set::antirandom::ban-reason missing"); errors++; }

*errs = errors;
return errors ? -1 : 1;
}

static int init_stuff(void)
{
if (!init_sregexes() || !init_triples())
return 0;
return 1;
}

/** Initializes the sregexes regex list */
static int init_sregexes(void)
{
#ifndef _WIN32
ScoreTable *s = &regex_scores[0];
RegexList *e, *last=NULL;
int cnt=0, n;
char *res;

for (s=&regex_scores[0]; s->regex; s++)
{
cnt++;
e = MyMallocEx(sizeof(RegexList));
/* validate regex */
res = unreal_checkregex(s->regex, 0, 1);
if (res)
{
config_error("init_sregexes: sregexes_txt contains invalid regex (nr %d): %s",
cnt, res);
return 0;
}
/* parse regex here (should go fine, checked above) */
n = regcomp(&e->regex, s->regex, REG_ICASE|REG_EXTENDED);
if (n)
{
/* should never happen (yes I'm too lazy to get the errormsg) */
config_error("init_sregexes: weird regcomp() failure: item=%d, errorcode=%d, aborting...",
cnt, n);
return 0;
}
#ifdef DEBUGMODE
e->regextxt = strdup(s->regex);
#endif

e->score = s->score;

/* Append at end of list (to keep it in order, not importent yet, but..) */
if (last)
last->next = e;
else
sregexes = e; /*(head)*/
last = e;
}
#endif
return 1;
}

/** Initializes the triples list. */
static int init_triples(void)
{
char **s;
Triples *e, *last=NULL;
int cnt=0;

for (s=triples_txt; *s; *s++)
{
cnt++;
e = MyMallocEx(sizeof(Triples));
if (strlen(*s) > 2)
{
config_error("init_triples: error parsing triples_txt, cnt=%d, item='%s' (length>2)",
cnt, *s);
return 0;
}
strcpy(e->two, *s); /* (SAFE) */
*s++;
if (!*s)
{
config_error("init_triples: error parsing triples_txt, cnt=%d, got NULL expected param",
cnt);
return 0;
}
if (strlen(*s) > TRIPLES_REST_SIZE-1)
{
config_error("init_triples: error parsing triples_txt, cnt=%d, item='%s' (length>%d)",
cnt, *s, TRIPLES_REST_SIZE-1);
return 0;
}
strcpy(e->rest, *s); /* (SAFE) */

/* Append at end of list (to keep it in order, not importent yet, but..) */
if (last)
last->next = e;
else
triples = e; /*(head)*/
last = e;
}
return 1;
}

/** Run the actual tests over this string.
* There are 3 tests:
* - weird chars (not used)
* - sregexes (easy stuff)
* - triples (three-letter combinations)
*/
static int internal_getscore(char *str)
{
#ifndef _WIN32
RegexList *r;
#endif
Triples *t;
register char *s;
int score = 0;
int highest_vowels=0, highest_consonants=0, highest_digits=0;
int vowels=0, consonants=0, digits=0;

#ifndef _WIN32
for (r=sregexes; r; r=r->next)
{
if (!regexec(&r->regex, str, 0, NULL, 0))
{
score += r->score; /* note: in the draft this returns the # of occurances, not 1 */
#ifdef DEBUGMODE
sendto_realops("score@'%s': MATCH for '%s'", str, r->regextxt);
#endif
}
}
#endif

/* Fast digit/consonant/vowel checks... */
for (s=str; *s; s++)
{
if ((*s >= '0') && (*s <= '9'))
digits++;
else {
highest_digits = MAX(highest_digits, digits);
digits = 0;
}
if (strchr("bcdfghjklmnpqrstvwxz", *s))
consonants++;
else {
highest_consonants = MAX(highest_consonants, consonants);
consonants = 0;
}
if (strchr("aeiou", *s))
vowels++;
else {
highest_vowels = MAX(highest_vowels, vowels);
vowels = 0;
}
}

digits = MAX(highest_digits, digits);
consonants = MAX(highest_consonants, consonants);
vowels = MAX(highest_vowels, vowels);

if (digits >= 5)
{
score += 5 + (digits - 5);
#ifdef DEBUGMODE
sendto_realops("score@'%s': MATCH for digits check", str);
#endif
}
if (vowels >= 4)
{
score += 4 + (vowels - 4);
#ifdef DEBUGMODE
sendto_realops("score@'%s': MATCH for vowels check", str);
#endif
}
if (consonants >= 4)
{
score += 4 + (consonants - 4);
#ifdef DEBUGMODE
sendto_realops("score@'%s': MATCH for consonants check", str);
#endif
}

for (t=triples; t; t=t->next)
{
for (s=str; *s; s++)
if ((t->two[0] == s[0]) && (t->two[1] == s[1]) && s[2] && strchr(t->rest, s[2]))
{
score++; /* OK */
#ifdef DEBUGMODE
sendto_realops("score@'%s': MATCH for '%s[%s]' %c/%c/%c", str, t->two, t->rest,
s[0], s[1], s[2]);
#endif
}
}



return score;
}

/** Returns "spam score".
* @note a user is expected, do not call for anything else (eg: servers)
*/
static int get_spam_score(aClient *sptr)
{
char *nick = sptr->name;
char *user = sptr->user->username;
char *gecos = sptr->info;
int nscore, uscore, gscore, score;
#ifdef TIMING
struct timeval tv_alpha, tv_beta;

gettimeofday(&tv_alpha, NULL);
#endif
nscore = internal_getscore(nick);
uscore = internal_getscore(user);
gscore = internal_getscore(gecos);
score = nscore + uscore + gscore;

#ifdef TIMING
gettimeofday(&tv_beta, NULL);
ircd_log(LOG_ERROR, "AntiRandom Timing: %ld microseconds",
((tv_beta.tv_sec - tv_alpha.tv_sec) * 1000000) + (tv_beta.tv_usec - tv_alpha.tv_usec));
#endif
#ifdef DEBUGMODE
sendto_realops("got score: %d/%d/%d = %d",
nscore, uscore, gscore, score);
#endif

return score;
}

void check_all_users(void)
{
aClient *acptr;
int i, matches=0, score;

for (i = LastSlot; i >= 0; i--)
{
if ((acptr = local[i]) && IsPerson(acptr))
{
if (is_except_host(acptr))
continue;

score = get_spam_score(acptr);
if (score > cfg.threshold)
{
if (!matches)
sendto_realops("[antirandom] Full status report follows:");
sendto_realops("%d points: %s!%s@%s:%s",
score, acptr->name, acptr->user->username, acptr->user->realhost, acptr->info);
matches++;
}
}
}
if (matches)
sendto_realops("[antirandom] %d match%s", matches, matches == 1 ? "" : "es");
}

DLLFUNC int antirandom_preconnect(aClient *sptr)
{
int score;

if (!is_except_host(sptr))
{
score = get_spam_score(sptr);
if (score > cfg.threshold)
{
if (cfg.show_failedconnects)
sendto_realops("[antirandom] denied access to user with score %d: %s!%s@%s:%s",
score, sptr->name, sptr->user->username, sptr->user->realhost, sptr->info);
return place_host_ban(sptr, cfg.ban_action, cfg.ban_reason, cfg.ban_time);
}
}
return 0;
}

static void free_stuff(void)
{
#ifndef _WIN32
RegexList *r, *r_next;
#endif
Triples *t, *t_next;

#ifndef _WIN32
for (r=sregexes; r; r=r_next)
{
r_next = r->next;
regfree(&r->regex);
#ifdef DEBUGMODE
if (r->regextxt)
MyFree(r->regextxt);
#endif
MyFree(r);
}
sregexes = NULL;
#endif

for (t=triples; t; t=t_next)
{
t_next = t->next;
MyFree(t);
}
triples = NULL;
}

/** Finds out if the host is on the except list. 1 if yes, 0 if no */
static int is_except_host(aClient *sptr)
{
char *host, *ip;
DynList *d;
#ifdef TIMING
struct timeval tv_alpha, tv_beta;

gettimeofday(&tv_alpha, NULL);
#endif

host = sptr->user ? sptr->user->realhost : "???";
ip = GetIP(sptr) ? GetIP(sptr) : "???";

for (d=cfg.except_hosts; d; d=d->next)
if (!match(d->entry, host) || !match(d->entry, ip))
return 1;

#ifdef TIMING
gettimeofday(&tv_beta, NULL);
ircd_log(LOG_ERROR, "AntiRandom is_except_host (full search): %ld microseconds",
((tv_beta.tv_sec - tv_alpha.tv_sec) * 1000000) + (tv_beta.tv_usec - tv_alpha.tv_usec));
#endif
return 0;
}

King_of_Night
05-10-2006, 20:16
/*
* ================================================== ===============
* Filename: cmdflood.c
* Description: Flood protection for commands.
* Written by: AngryWolf <angrywolf@flashmail.com>
* Requested by: aaadicted
* Documentation: cmdflood.txt (comes with the package)
* ================================================== ===============
*/

#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef STRIPBADWORDS
#include "badwords.h"
#endif
#ifdef _WIN32
#include "version.h"
#endif

typedef struct _floodsetting FloodSetting;
typedef struct _floodinfo FloodInfo;

struct _floodsetting
{
FloodSetting *prev, *next;
char *cmd;
Cmdoverride *ovr;
int count;
int period;
};

struct _floodinfo
{
FloodInfo *prev, *next;
aClient *cptr;
char *cmd;
int count;
TS last;
};

extern void sendto_one(aClient *to, char *pattern, ...);
extern void sendto_realops(char *pattern, ...);
extern int config_parse_flood(char *orig, int *times, int *period);

#define MSG_CMDFLOOD "CMDFLOOD"
#define TOK_CMDFLOOD "CF"
#define ERR_TOOMANYUSES ":%s 495 %s :Too many uses of command %s. Wait %d seconds before trying again."
#define DelOverride(cmd, ovr) if (ovr && CommandExists(cmd)) CmdoverrideDel(ovr); ovr = NULL
#define DelHook(x) if (x) HookDel(x); x = NULL
#define DelCommand(x) if (x) CommandDel(x); x = NULL
#define ircstrdup(x,y) if (x) MyFree(x); if (!y) x = NULL; else x = strdup(y)
#define ircfree(x) if (x) MyFree(x); x = NULL

static Command *AddCommand(Module *module, char *msg, char *token, iFP func);
static Cmdoverride *AddOverride(char *msg, iFP cb);
static int m_cmdflood(aClient *cptr, aClient *sptr, int parc, char *parv[]);
static int override_cmd(Cmdoverride *, aClient *, aClient *, int, char *[]);
static int cb_config_test(ConfigFile *, ConfigEntry *, int, int *);
static int cb_config_run(ConfigFile *, ConfigEntry *, int);
static int cb_config_rehash();
static int cb_quit(aClient *, char *);
static FloodSetting *find_FloodSetting(char *cmd);
static FloodInfo *find_FloodInfo(aClient *cptr, char *cmd);
static void FreeFloodSettings();
static void FreeFloodInfoList();
static void InitConf();
static void FreeConf();
#ifdef HOOKTYPE_REHASH_COMPLETE
static int cb_rehash_complete();
#else
static EVENT(LoadOverrides);
#endif

static Command *CmdCmdflood;
static Hook *HookConfTest, *HookConfRun, *HookConfRehash;
static Hook *HookQuit;
#ifdef STATIC_LINKING
#ifdef HOOKTYPE_REHASH_COMPLETE
static Hook *HookRehashDone;
#else
static u_int event_added;
#endif
#endif
static FloodSetting *FloodSettings;
static FloodInfo *FloodInfoList;

#ifndef STATIC_LINKING
static ModuleInfo *MyModInfo;
#define MyMod MyModInfo->handle
#define SAVE_MODINFO MyModInfo = modinfo;
#else
#define MyMod NULL
#define SAVE_MODINFO
#endif

ModuleHeader MOD_HEADER(cmdflood)
= {
"cmdflood",
"$Id: cmdflood.c,v 1.8 2004/05/17 19:58:06 angrywolf Exp $",
"Flood protection for commands",
"3.2-b8-1",
NULL
};

DLLFUNC int MOD_TEST(cmdflood)(ModuleInfo *modinfo)
{
SAVE_MODINFO
HookConfTest = HookAddEx(modinfo->handle, HOOKTYPE_CONFIGTEST, cb_config_test);

return MOD_SUCCESS;
}

DLLFUNC int MOD_INIT(cmdflood)(ModuleInfo *modinfo)
{
SAVE_MODINFO
FloodInfoList = NULL;

#ifndef STATIC_LINKING
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM);
#endif
InitConf();

HookConfRun = HookAddEx(modinfo->handle, HOOKTYPE_CONFIGRUN, cb_config_run);
HookConfRehash = HookAddEx(modinfo->handle, HOOKTYPE_REHASH, cb_config_rehash);
#if defined(HOOKTYPE_REHASH_COMPLETE) && defined(STATIC_LINKING)
HookRehashDone = HookAddEx(modinfo->handle, HOOKTYPE_REHASH_COMPLETE, cb_rehash_complete);
#endif
HookQuit = HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_QUIT, cb_quit);
CmdCmdflood = AddCommand(modinfo->handle, MSG_CMDFLOOD, TOK_CMDFLOOD, m_cmdflood);

if (!CmdCmdflood)
return MOD_FAILED;

return MOD_SUCCESS;
}

DLLFUNC int MOD_LOAD(cmdflood)(int module_load)
{
#ifdef HOOKTYPE_REHASH_COMPLETE
cb_rehash_complete();
#else
LoadOverrides(NULL);
#endif

return MOD_SUCCESS;
}

DLLFUNC int MOD_UNLOAD(cmdflood)(int module_unload)
{
FreeConf();
FreeFloodInfoList();

#if defined(HOOKTYPE_REHASH_COMPLETE) && defined(STATIC_LINKING)
DelHook(HookRehashDone);
#endif
DelHook(HookQuit);
DelHook(HookConfRehash);
DelHook(HookConfRun);