/* * ================================================================= * Filename: regexban.c * Description: Extended ban type ~R * Author: AngryWolf * Documentation: regexban.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 #include #include #include #include #ifdef _WIN32 #include #endif #include #include "h.h" #ifdef STRIPBADWORDS #include "badwords.h" #endif #ifdef _WIN32 #include "version.h" #endif extern void sendto_one(aClient *to, char *pattern, ...); #define FLAG_REGEXBAN 'R' #define DEF_REGFLAGS (REG_ICASE | REG_EXTENDED | REG_NOSUB) #define DelExtban(x) if (x) ExtbanDel(x); x = NULL static Extban *AddExtban(Module *module, ExtbanInfo *req); static int regexban_is_ok(aClient *, aChannel *, char *, int, int, int); static char *regexban_conv_param(char *); static int regexban_is_banned(aClient *, aChannel *, char *, int); Extban *ExtbanRegex; regex_t expr; ModuleHeader MOD_HEADER(regexban) = { "regexban", "$Id: regexban.c,v 2.1 2004/07/12 21:54:19 angrywolf Exp $", "Extended ban type ~R (ban masks with regular expressions)", "3.2-b8-1", NULL }; DLLFUNC int MOD_INIT(regexban)(ModuleInfo *modinfo) { ExtbanInfo req; memset(&req, 0, sizeof req); req.flag = FLAG_REGEXBAN; req.is_ok = regexban_is_ok; req.conv_param = regexban_conv_param; req.is_banned = regexban_is_banned; ExtbanRegex = AddExtban(modinfo->handle, &req); if (!ExtbanRegex) return MOD_FAILED; return MOD_SUCCESS; } DLLFUNC int MOD_LOAD(regexban)(int module_load) { return MOD_SUCCESS; } DLLFUNC int MOD_UNLOAD(regexban)(int module_unload) { DelExtban(ExtbanRegex); return MOD_FAILED; } Extban *AddExtban(Module *module, ExtbanInfo *req) { Extban *ban = ExtbanAdd(module, *req); #ifndef STATIC_LINKING if (ModuleGetError(module) != MODERR_NOERROR || !ban) #else if (!ban) #endif { #ifndef STATIC_LINKING config_error("Error adding extended ban type %c when loading module %s: %s", req->flag, MOD_HEADER(regexban).name, ModuleGetErrorStr(module)); #else config_error("Error adding extended ban type %c when loading module %s", req->flag, MOD_HEADER(regexban).name); #endif return NULL; } return ban; } /* * Checks the validity of a regular expression. If there was no error, * returns NULL, otherwise a pointer to a string which must be free'd * up by the caller. */ static char *check_regex(char *mask) { int errorcode, errorbufsize; char *errorbuf = NULL; memset(&expr, 0, sizeof expr); errorcode = regcomp(&expr, mask, DEF_REGFLAGS); if (errorcode > 0) { errorbufsize = regerror(errorcode, &expr, NULL, 0) + 1; errorbuf = MyMalloc(errorbufsize); regerror(errorcode, &expr, errorbuf, errorbufsize); } regfree(&expr); return errorbuf; } static int regexban_is_ok(aClient *sptr, aChannel *chptr, char *tmpstr, int ctype, int what, int etype) { char *mask = tmpstr + 3; switch (ctype) { case EXBCHK_PARAM: { char *errmsg; if (!*mask) { sendto_one(sptr, ":%s NOTICE %s :Invalid ban mask", me.name, sptr->name); return 0; } if ((errmsg = check_regex(mask))) { sendto_one(sptr, ":%s NOTICE %s :Ban mask contains an invalid regex: %s", me.name, sptr->name, errmsg); MyFree(errmsg); return 0; } break; } case EXBCHK_ACCESS: case EXBCHK_ACCESS_ERR: { if (!is_chan_op(sptr, chptr)) { if (ctype == EXBCHK_ACCESS_ERR) sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, sptr->name, chptr->chname); return 0; } break; } } return 1; } static char *regexban_conv_param(char *mask) { return mask; } static int regexban_is_banned(aClient *sptr, aChannel *chptr, char *mask, int type) { if (!((type == BANCHK_JOIN) || (type == BANCHK_MSG) || (type == BANCHK_NICK))) return 0; /* Not the fastest code... */ memset(&expr, 0, sizeof expr); regcomp(&expr, mask + 3, DEF_REGFLAGS); if ((ban_realhost && !regexec(&expr, ban_realhost, 0, NULL, 0)) || (ban_virthost && !regexec(&expr, ban_virthost, 0, NULL, 0)) || (ban_ip && !regexec(&expr, ban_ip, 0, NULL, 0))) return 1; return 0; }