1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-26 04:46:37 +02:00
Files
unrealircd/src/modules.c
T
Bram Matthys dddc8f07e4 PROTOCTL EAUTH/SERVERS/new linking protocol:
- Server protocol: added PROTOCTL EATH=servername, which allows us to
  authenticate the server very early in the handshake process. That way,
  certain commands and PROTOCTL tokens can 'trust' the server.
  See doc/technical/protoctl.txt for details.
- Server protocol: between new Unreal servers we now do the handshake a
  little bit different, so it waits with sending the SERVER command until
  the first PROTOCTL is received. Needed for next.
- Server protocol: added PROTOCTL SERVERS=1,2,3,4,etc by which a server can
  inform the other server which servers (server numeric, actually) it has
  linked. See doc/technical/protoctl.txt and next for details.
- When our server was trying to link to some server, and at the same time
  another server was also trying to link with us, this would lead to a
  server collision: the server would link (twice) ok at first, but then a
  second later or so both would quit with 'Server Exists' with quite some
  mess as a result. This isn't unique to Unreal, btw.
  This happened more often when you had a low connfreq in your link blocks
  (aka: quick reconnects), or had multiple hubs on autoconnect (with same
  connfreq), or when you (re)started all servers at the same time.
  This should now be solved by a new server handshake design, which detects
  this race condition and solves it by closing one of the two (or more)
  connections to avoid the issue.
  This also means that it should now be safe to have multiple hubs with low
  connfreq's (eg: 10s) without risking that your network falls apart.
  This new server handshake (protocol updates, etc) was actually quite some
  work, especially for something that only happened sporadically. I felt it
  was needed though, because (re)linking stability is extremely important.
  This new feature/design/fix requires extensive testing.
  This feature can be disabled by: set { new-linking-protocol 0; };
2010-01-01 19:49:06 +00:00

1758 lines
42 KiB
C

/************************************************************************
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/modules.c
* (C) 2001 Carsten Munk (Techie/Stskeeps) <stskeeps@tspre.org>
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* 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.
*
* $Id$
*/
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include "version.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifdef _WIN32
#include <io.h>
#define RTLD_NOW 0
const char *our_dlerror(void);
#elif defined(HPUX)
#include <dl.h>
#define RTLD_NOW BIND_IMMEDIATE
#else
#include <dlfcn.h>
#endif
#include <fcntl.h>
#ifndef _WIN32
#include <dirent.h>
#endif
#include "h.h"
#include "proto.h"
#ifndef RTLD_NOW
#define RTLD_NOW RTLD_LAZY
#endif
#define UNREALCORE
#include "modversion.h"
Hook *Hooks[MAXHOOKTYPES];
Hooktype Hooktypes[MAXCUSTOMHOOKS];
Callback *Callbacks[MAXCALLBACKS]; /* Callback objects for modules, used for rehashing etc (can be multiple) */
Callback *RCallbacks[MAXCALLBACKS]; /* 'Real' callback function, used for callback function calls */
Efunction *Efunctions[MAXEFUNCTIONS]; /* Efunction objects (used for rehashing) */
MODVAR Module *Modules = NULL;
MODVAR Versionflag *Versionflags = NULL;
int Module_Depend_Resolve(Module *p, char *path);
Module *Module_make(ModuleHeader *header,
#ifdef _WIN32
HMODULE mod
#else
void *mod
#endif
);
typedef struct {
char *name;
void **funcptr;
} EfunctionsList;
/* Efuncs */
int (*do_join)(aClient *cptr, aClient *sptr, int parc, char *parv[]);
void (*join_channel)(aChannel *chptr, aClient *cptr, aClient *sptr, int flags);
int (*can_join)(aClient *cptr, aClient *sptr, aChannel *chptr, char *key, char *link, char *parv[]);
void (*do_mode)(aChannel *chptr, aClient *cptr, aClient *sptr, int parc, char *parv[], time_t sendts, int samode);
void (*set_mode)(aChannel *chptr, aClient *cptr, int parc, char *parv[], u_int *pcount,
char pvar[MAXMODEPARAMS][MODEBUFLEN + 3], int bounce);
int (*m_umode)(aClient *cptr, aClient *sptr, int parc, char *parv[]);
int (*register_user)(aClient *cptr, aClient *sptr, char *nick, char *username, char *umode, char *virthost, char *ip);
int (*tkl_hash)(unsigned int c);
char (*tkl_typetochar)(int type);
aTKline *(*tkl_add_line)(int type, char *usermask, char *hostmask, char *reason, char *setby,
TS expire_at, TS set_at, TS spamf_tkl_duration, char *spamf_tkl_reason);
aTKline *(*tkl_del_line)(aTKline *tkl);
void (*tkl_check_local_remove_shun)(aTKline *tmp);
aTKline *(*tkl_expire)(aTKline * tmp);
EVENT((*tkl_check_expire));
int (*find_tkline_match)(aClient *cptr, int xx);
int (*find_shun)(aClient *cptr);
int(*find_spamfilter_user)(aClient *sptr, int flags);
aTKline *(*find_qline)(aClient *cptr, char *nick, int *ishold);
int (*find_tkline_match_zap)(aClient *cptr);
void (*tkl_stats)(aClient *cptr, int type, char *para);
void (*tkl_synch)(aClient *sptr);
int (*m_tkl)(aClient *cptr, aClient *sptr, int parc, char *parv[]);
int (*place_host_ban)(aClient *sptr, int action, char *reason, long duration);
int (*dospamfilter)(aClient *sptr, char *str_in, int type, char *target, int flags, aTKline **rettk);
int (*dospamfilter_viruschan)(aClient *sptr, aTKline *tk, int type);
int (*find_tkline_match_zap_ex)(aClient *cptr, aTKline **rettk);
void (*send_list)(aClient *cptr, int numsend);
char *(*stripbadwords_channel)(char *str, int *blocked);
char *(*stripbadwords_message)(char *str, int *blocked);
char *(*stripbadwords_quit)(char *str, int *blocked);
unsigned char *(*StripColors)(unsigned char *text);
const char *(*StripControlCodes)(unsigned char *text);
void (*spamfilter_build_user_string)(char *buf, char *nick, aClient *acptr);
int (*is_silenced)(aClient *sptr, aClient *acptr);
void (*send_protoctl_servers)(aClient *sptr, int response);
int (*verify_link)(aClient *cptr, aClient *sptr, char *servername, ConfigItem_link **link_out);
static const EfunctionsList efunction_table[MAXEFUNCTIONS] = {
/* 00 */ {NULL, NULL},
/* 01 */ {"do_join", (void *)&do_join},
/* 02 */ {"join_channel", (void *)&join_channel},
/* 03 */ {"can_join", (void *)&can_join},
/* 04 */ {"do_mode", (void *)&do_mode},
/* 05 */ {"set_mode", (void *)&set_mode},
/* 06 */ {"m_umode", (void *)&m_umode},
/* 07 */ {"register_user", (void *)&register_user},
/* 08 */ {"tkl_hash", (void *)&tkl_hash},
/* 09 */ {"tkl_typetochar", (void *)&tkl_typetochar},
/* 10 */ {"tkl_add_line", (void *)&tkl_add_line},
/* 11 */ {"tkl_del_line", (void *)&tkl_del_line},
/* 12 */ {"tkl_check_local_remove_shun", (void *)&tkl_check_local_remove_shun},
/* 13 */ {"tkl_expire", (void *)&tkl_expire},
/* 14 */ {"tkl_check_expire", (void *)&tkl_check_expire},
/* 15 */ {"find_tkline_match", (void *)&find_tkline_match},
/* 16 */ {"find_shun", (void *)&find_shun},
/* 17 */ {"find_spamfilter_user", (void *)&find_spamfilter_user},
/* 18 */ {"find_qline", (void *)&find_qline},
/* 19 */ {"find_tkline_match_zap", (void *)&find_tkline_match_zap},
/* 20 */ {"tkl_stats", (void *)&tkl_stats},
/* 21 */ {"tkl_synch", (void *)&tkl_synch},
/* 22 */ {"m_tkl", (void *)&m_tkl},
/* 23 */ {"place_host_ban", (void *)&place_host_ban},
/* 24 */ {"dospamfilter", (void *)&dospamfilter},
/* 25 */ {"dospamfilter_viruschan", (void *)&dospamfilter_viruschan},
/* 26 */ {"find_tkline_match_zap_ex", (void *)&find_tkline_match_zap_ex},
/* 27 */ {"send_list", (void *)&send_list},
/* 28 */ {"stripbadwords_channel", (void *)&stripbadwords_channel},
/* 29 */ {"stripbadwords_message", (void *)&stripbadwords_message},
/* 30 */ {"stripbadwords_quit", (void *)&stripbadwords_quit},
/* 31 */ {"StripColors", (void *)&StripColors},
/* 32 */ {"StripControlCodes", (void *)&StripControlCodes},
/* 33 */ {"spamfilter_build_user_string", (void *)&spamfilter_build_user_string},
/* 34 */ {"is_silenced", (void *)&is_silenced},
/* 35 */ {"send_protoctl_servers", (void *)&send_protoctl_servers},
/* 36 */ {"verify_link", (void *)&verify_link},
/* 37 */ {NULL, NULL}
};
#ifdef UNDERSCORE
void *obsd_dlsym(void *handle, char *symbol) {
char *obsdsymbol = (char*)MyMalloc(strlen(symbol) + 2);
void *symaddr = NULL;
if (obsdsymbol) {
sprintf(obsdsymbol, "_%s", symbol);
symaddr = dlsym(handle, obsdsymbol);
free(obsdsymbol);
}
return symaddr;
}
#endif
void DeleteTempModules(void)
{
char tempbuf[PATH_MAX+1];
#ifndef _WIN32
DIR *fd = opendir("tmp");
struct dirent *dir;
if (!fd) /* Ouch.. this is NOT good!! */
{
config_error("Unable to open 'tmp' directory: %s, please create one with the appropriate permissions",
strerror(errno));
if (!loop.ircd_booted)
exit(7);
return;
}
while ((dir = readdir(fd)))
{
if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
continue;
strcpy(tempbuf, "tmp/");
strcat(tempbuf, dir->d_name);
remove(tempbuf);
}
closedir(fd);
#else
WIN32_FIND_DATA hData;
HANDLE hFile = FindFirstFile("tmp/*", &hData);
if (hFile != INVALID_HANDLE_VALUE)
{
if (strcmp(hData.cFileName, ".") || strcmp(hData.cFileName, ".."))
{
strcpy(tempbuf, "tmp/");
strcat(tempbuf, hData.cFileName);
remove(tempbuf);
}
}
while (FindNextFile(hFile, &hData))
{
if (!strcmp(hData.cFileName, ".") || !strcmp(hData.cFileName, ".."))
continue;
strcpy(tempbuf, "tmp/");
strcat(tempbuf, hData.cFileName);
remove(tempbuf);
}
FindClose(hFile);
#endif
}
void Module_Init(void)
{
bzero(Hooks, sizeof(Hooks));
bzero(Hooktypes, sizeof(Hooktypes));
bzero(Callbacks, sizeof(Callback));
bzero(RCallbacks, sizeof(Callback));
bzero(Efunctions, sizeof(Efunction));
}
Module *Module_Find(char *name)
{
Module *p;
for (p = Modules; p; p = p->next)
{
if (!(p->options & MOD_OPT_PERM) &&
(!(p->flags & MODFLAG_TESTING) || (p->flags & MODFLAG_DELAYED)))
continue;
if (!strcmp(p->header->name, name))
{
return (p);
}
}
return NULL;
}
int parse_modsys_version(char *version)
{
int betaversion, tag;
if (!strcmp(version, "3.2.3"))
return 0x32300;
if (sscanf(version, "3.2-b%d-%d", &betaversion, &tag))
{
switch (betaversion)
{
case 5:
return 0x320b5;
case 6:
return 0x320b6;
case 7:
return 0x320b7;
case 8:
return 0x320b8;
default:
return 0;
}
}
return 0;
}
void make_compiler_string(char *buf, unsigned int ver)
{
unsigned int maj, min, plevel;
if (ver == 0)
{
strcpy(buf, "0");
return;
}
maj = ver >> 16;
min = (ver >> 8) & 0xff;
plevel = ver & 0xff;
if (plevel == 0)
sprintf(buf, "%d.%d", maj, min);
else
sprintf(buf, "%d.%d.%d", maj, min, plevel);
}
/*
* Returns an error if insucessful .. yes NULL is OK!
*/
char *Module_Create(char *path_)
{
#ifndef STATIC_LINKING
#ifdef _WIN32
HMODULE Mod;
#else /* _WIN32 */
void *Mod;
#endif /* _WIN32 */
int (*Mod_Test)();
int (*Mod_Init)();
int (*Mod_Load)();
int (*Mod_Unload)();
char *Mod_Version;
unsigned int *compiler_version;
static char errorbuf[1024];
char *path, *tmppath;
ModuleHeader *mod_header = NULL;
int ret = 0;
Module *mod = NULL, **Mod_Handle = NULL;
char *expectedmodversion = our_mod_version;
unsigned int expectedcompilerversion = our_compiler_version;
long modsys_ver = 0;
Debug((DEBUG_DEBUG, "Attempting to load module from %s",
path_));
path = path_;
tmppath = unreal_mktemp("tmp", unreal_getfilename(path));
if (!tmppath)
return "Unable to create temporary file!";
#ifndef _WIN32
if(!strchr(path, '/'))
#else
if (!strchr(path, '\\') && !strchr(path, '/'))
#endif
{
path = MyMalloc(strlen(path) + 3);
strcpy(path, "./");
strcat(path, path_);
}
if (!file_exists(path))
{
snprintf(errorbuf, sizeof(errorbuf), "Cannot open module file: %s", strerror(errno));
return errorbuf;
}
/* For OpenBSD, do not do a hardlinkink attempt first because it checks inode
* numbers to see if a certain module is already loaded. -- Syzop
* EDIT (2009): Looks like Linux got smart too, from now on we always copy....
*/
ret = unreal_copyfileex(path, tmppath, 0);
if (!ret)
{
snprintf(errorbuf, sizeof(errorbuf), "Failed to copy module file.");
return errorbuf;
}
if ((Mod = irc_dlopen(tmppath, RTLD_NOW)))
{
/* We have engaged the borg cube. Scan for lifesigns. */
irc_dlsym(Mod, "Mod_Version", Mod_Version);
if (Mod_Version && strcmp(Mod_Version, expectedmodversion))
{
snprintf(errorbuf, sizeof(errorbuf),
"Module was compiled for '%s', we were configured for '%s'. SOLUTION: Recompile the module(s).",
Mod_Version, expectedmodversion);
irc_dlclose(Mod);
remove(tmppath);
return errorbuf;
}
if (!Mod_Version)
{
snprintf(errorbuf, sizeof(errorbuf),
"Module is lacking Mod_Version. Perhaps a very old one you forgot to recompile?");
irc_dlclose(Mod);
remove(tmppath);
return errorbuf;
}
irc_dlsym(Mod, "compiler_version", compiler_version);
if (compiler_version && ( ((*compiler_version) & 0xffff00) != (expectedcompilerversion & 0xffff00) ) )
{
char theyhad[64], wehave[64];
make_compiler_string(theyhad, *compiler_version);
make_compiler_string(wehave, expectedcompilerversion);
snprintf(errorbuf, sizeof(errorbuf),
"Module was compiled with GCC %s, core was compiled with GCC %s. SOLUTION: Recompile your UnrealIRCd and all it's modules by doing a 'make clean; ./Config -quick && make'.",
theyhad, wehave);
irc_dlclose(Mod);
remove(tmppath);
return errorbuf;
}
irc_dlsym(Mod, "Mod_Header", mod_header);
if (!mod_header)
{
irc_dlclose(Mod);
remove(tmppath);
return ("Unable to locate Mod_Header");
}
if (!mod_header->modversion)
{
irc_dlclose(Mod);
remove(tmppath);
return ("Lacking mod_header->modversion");
}
if (!(modsys_ver = parse_modsys_version(mod_header->modversion)))
{
snprintf(errorbuf, 1023, "Unsupported module system version '%s'",
mod_header->modversion);
irc_dlclose(Mod);
remove(tmppath);
return(errorbuf);
}
if (!mod_header->name || !mod_header->version ||
!mod_header->description)
{
irc_dlclose(Mod);
remove(tmppath);
return("Lacking sane header pointer");
}
if (Module_Find(mod_header->name))
{
irc_dlclose(Mod);
remove(tmppath);
return (NULL);
}
mod = (Module *)Module_make(mod_header, Mod);
mod->tmp_file = strdup(tmppath);
mod->mod_sys_version = modsys_ver;
mod->compiler_version = compiler_version ? *compiler_version : 0;
irc_dlsym(Mod, "Mod_Init", Mod_Init);
if (!Mod_Init)
{
Module_free(mod);
return ("Unable to locate Mod_Init");
}
irc_dlsym(Mod, "Mod_Unload", Mod_Unload);
if (!Mod_Unload)
{
Module_free(mod);
return ("Unable to locate Mod_Unload");
}
irc_dlsym(Mod, "Mod_Load", Mod_Load);
if (!Mod_Load)
{
Module_free(mod);
return ("Unable to locate Mod_Load");
}
if (Module_Depend_Resolve(mod, path) == -1)
{
Module_free(mod);
return ("Dependancy problem");
}
irc_dlsym(Mod, "Mod_Handle", Mod_Handle);
if (Mod_Handle)
*Mod_Handle = mod;
irc_dlsym(Mod, "Mod_Test", Mod_Test);
if (Mod_Test)
{
if (mod->mod_sys_version >= 0x320b8) {
if ((ret = (*Mod_Test)(&mod->modinfo)) < MOD_SUCCESS) {
ircsprintf(errorbuf, "Mod_Test returned %i",
ret);
/* We EXPECT the module to have cleaned up it's mess */
Module_free(mod);
return (errorbuf);
}
}
else {
if ((ret = (*Mod_Test)(0)) < MOD_SUCCESS)
{
snprintf(errorbuf, 1023, "Mod_Test returned %i",
ret);
/* We EXPECT the module to have cleaned up it's mess */
Module_free(mod);
return (errorbuf);
}
}
}
mod->flags = MODFLAG_TESTING;
AddListItem(mod, Modules);
return NULL;
}
else
{
/* Return the error .. */
return ((char *)irc_dlerror());
}
if (path != path_)
free(path);
#else /* !STATIC_LINKING */
return "We don't support dynamic linking";
#endif
}
void Module_DelayChildren(Module *m)
{
ModuleChild *c;
for (c = m->children; c; c = c->next)
{
c->child->flags |= MODFLAG_DELAYED;
Module_DelayChildren(c->child);
}
}
Module *Module_make(ModuleHeader *header,
#ifdef _WIN32
HMODULE mod
#else
void *mod
#endif
)
{
Module *modp = NULL;
modp = (Module *)MyMallocEx(sizeof(Module));
modp->header = header;
modp->dll = mod;
modp->flags = MODFLAG_NONE;
modp->options = 0;
modp->errorcode = MODERR_NOERROR;
modp->children = NULL;
modp->modinfo.size = sizeof(ModuleInfo);
modp->modinfo.module_load = 0;
modp->modinfo.handle = modp;
return (modp);
}
void Init_all_testing_modules(void)
{
Module *mi, *next;
int ret;
iFP Mod_Init;
for (mi = Modules; mi; mi = next)
{
next = mi->next;
if (!(mi->flags & MODFLAG_TESTING))
continue;
irc_dlsym(mi->dll, "Mod_Init", Mod_Init);
if (mi->mod_sys_version >= 0x320b8) {
if ((ret = (*Mod_Init)(&mi->modinfo)) < MOD_SUCCESS) {
config_error("Error loading %s: Mod_Init returned %i",
mi->header->name, ret);
Module_free(mi);
continue;
}
}
else {
if ((ret = (*Mod_Init)(0)) < MOD_SUCCESS)
{
config_error("Error loading %s: Mod_Init returned %i",
mi->header->name, ret);
Module_free(mi);
continue;
}
}
mi->flags = MODFLAG_INIT;
}
}
void Unload_all_loaded_modules(void)
{
Module *mi, *next;
ModuleChild *child, *childnext;
ModuleObject *objs, *objnext;
iFP Mod_Unload;
int ret;
for (mi = Modules; mi; mi = next)
{
next = mi->next;
if (!(mi->flags & MODFLAG_LOADED) || (mi->flags & MODFLAG_DELAYED) || (mi->options & MOD_OPT_PERM))
continue;
irc_dlsym(mi->dll, "Mod_Unload", Mod_Unload);
if (Mod_Unload)
{
ret = (*Mod_Unload)(0);
if (ret == MOD_DELAY)
{
mi->flags |= MODFLAG_DELAYED;
Module_DelayChildren(mi);
}
}
for (objs = mi->objects; objs; objs = objnext) {
objnext = objs->next;
if (objs->type == MOBJ_EVENT) {
LockEventSystem();
EventDel(objs->object.event);
UnlockEventSystem();
}
else if (objs->type == MOBJ_HOOK) {
HookDel(objs->object.hook);
}
else if (objs->type == MOBJ_COMMAND) {
CommandDel(objs->object.command);
}
else if (objs->type == MOBJ_HOOKTYPE) {
HooktypeDel(objs->object.hooktype, mi);
}
else if (objs->type == MOBJ_VERSIONFLAG) {
VersionflagDel(objs->object.versionflag, mi);
}
else if (objs->type == MOBJ_SNOMASK) {
SnomaskDel(objs->object.snomask);
}
else if (objs->type == MOBJ_UMODE) {
UmodeDel(objs->object.umode);
}
else if (objs->type == MOBJ_CMODE) {
CmodeDel(objs->object.cmode);
}
else if (objs->type == MOBJ_CMDOVERRIDE) {
CmdoverrideDel(objs->object.cmdoverride);
}
else if (objs->type == MOBJ_EXTBAN) {
ExtbanDel(objs->object.extban);
}
else if (objs->type == MOBJ_CALLBACK) {
CallbackDel(objs->object.callback);
}
else if (objs->type == MOBJ_EFUNCTION) {
EfunctionDel(objs->object.efunction);
}
else if (objs->type == MOBJ_ISUPPORT) {
IsupportDel(objs->object.isupport);
}
}
for (child = mi->children; child; child = childnext)
{
childnext = child->next;
DelListItem(child,mi->children);
MyFree(child);
}
DelListItem(mi,Modules);
irc_dlclose(mi->dll);
#ifndef DEBUGMODE
remove(mi->tmp_file);
#endif
MyFree(mi->tmp_file);
MyFree(mi);
}
}
void Unload_all_testing_modules(void)
{
Module *mi, *next;
ModuleChild *child, *childnext;
ModuleObject *objs, *objnext;
for (mi = Modules; mi; mi = next)
{
next = mi->next;
if (!(mi->flags & MODFLAG_TESTING))
continue;
for (objs = mi->objects; objs; objs = objnext) {
objnext = objs->next;
if (objs->type == MOBJ_EVENT) {
LockEventSystem();
EventDel(objs->object.event);
UnlockEventSystem();
}
else if (objs->type == MOBJ_HOOK) {
HookDel(objs->object.hook);
}
else if (objs->type == MOBJ_COMMAND) {
CommandDel(objs->object.command);
}
else if (objs->type == MOBJ_HOOKTYPE) {
HooktypeDel(objs->object.hooktype, mi);
}
else if (objs->type == MOBJ_VERSIONFLAG) {
VersionflagDel(objs->object.versionflag, mi);
}
else if (objs->type == MOBJ_SNOMASK) {
SnomaskDel(objs->object.snomask);
}
else if (objs->type == MOBJ_UMODE) {
UmodeDel(objs->object.umode);
}
else if (objs->type == MOBJ_CMODE) {
CmodeDel(objs->object.cmode);
}
else if (objs->type == MOBJ_CMDOVERRIDE) {
CmdoverrideDel(objs->object.cmdoverride);
}
else if (objs->type == MOBJ_EXTBAN) {
ExtbanDel(objs->object.extban);
}
else if (objs->type == MOBJ_CALLBACK) {
CallbackDel(objs->object.callback);
}
else if (objs->type == MOBJ_EFUNCTION) {
EfunctionDel(objs->object.efunction);
}
else if (objs->type == MOBJ_ISUPPORT) {
IsupportDel(objs->object.isupport);
}
}
for (child = mi->children; child; child = childnext)
{
childnext = child->next;
DelListItem(child,mi->children);
MyFree(child);
}
DelListItem(mi,Modules);
irc_dlclose(mi->dll);
remove(mi->tmp_file);
MyFree(mi->tmp_file);
MyFree(mi);
}
}
/*
* Returns -1 if you cannot unload due to children still alive
* Returns 1 if successful
*/
int Module_free(Module *mod)
{
Module *p;
ModuleChild *cp, *cpnext;
ModuleObject *objs, *next;
/* Do not kill parent if children still alive */
for (cp = mod->children; cp; cp = cp->next)
{
sendto_realops("Unloading child module %s",
cp->child->header->name);
Module_Unload(cp->child->header->name, 0);
}
for (objs = mod->objects; objs; objs = next) {
next = objs->next;
if (objs->type == MOBJ_EVENT) {
LockEventSystem();
EventDel(objs->object.event);
UnlockEventSystem();
}
else if (objs->type == MOBJ_HOOK) {
HookDel(objs->object.hook);
}
else if (objs->type == MOBJ_COMMAND) {
CommandDel(objs->object.command);
}
else if (objs->type == MOBJ_HOOKTYPE) {
HooktypeDel(objs->object.hooktype, mod);
}
else if (objs->type == MOBJ_VERSIONFLAG) {
VersionflagDel(objs->object.versionflag, mod);
}
else if (objs->type == MOBJ_SNOMASK) {
SnomaskDel(objs->object.snomask);
}
else if (objs->type == MOBJ_UMODE) {
UmodeDel(objs->object.umode);
}
else if (objs->type == MOBJ_CMODE) {
CmodeDel(objs->object.cmode);
}
else if (objs->type == MOBJ_CMDOVERRIDE) {
CmdoverrideDel(objs->object.cmdoverride);
}
else if (objs->type == MOBJ_EXTBAN) {
ExtbanDel(objs->object.extban);
}
else if (objs->type == MOBJ_CALLBACK) {
CallbackDel(objs->object.callback);
}
else if (objs->type == MOBJ_EFUNCTION) {
EfunctionDel(objs->object.efunction);
}
else if (objs->type == MOBJ_ISUPPORT) {
IsupportDel(objs->object.isupport);
}
}
for (p = Modules; p; p = p->next)
{
for (cp = p->children; cp; cp = cpnext)
{
cpnext = cp->next;
if (cp->child == mod)
{
DelListItem(mod, p->children);
MyFree(cp);
/* We can assume there can be only one. */
break;
}
}
}
DelListItem(mod, Modules);
irc_dlclose(mod->dll);
MyFree(mod->tmp_file);
MyFree(mod);
return 1;
}
/*
* Module_Unload ()
* char *name Internal module name
* int unload If /module unload
* Returns:
* -1 Not able to locate module, severe failure, anything
* 1 Module unloaded
* 2 Module wishes delayed unloading, has placed event
*/
int Module_Unload(char *name, int unload)
{
Module *m;
int (*Mod_Unload)();
int ret;
for (m = Modules; m; m = m->next)
{
if (!strcmp(m->header->name, name))
{
break;
}
}
if (!m)
return -1;
irc_dlsym(m->dll, "Mod_Unload", Mod_Unload);
if (!Mod_Unload)
{
return -1;
}
ret = (*Mod_Unload)(unload);
if (ret == MOD_DELAY)
{
m->flags |= MODFLAG_DELAYED;
Module_DelayChildren(m);
return 2;
}
if (ret == MOD_FAILED)
{
return -1;
}
/* No more pain detected, let's unload */
DelListItem(m, Modules);
Module_free(m);
return 1;
}
vFP Module_SymEx(
#ifdef _WIN32
HMODULE mod
#else
void *mod
#endif
, char *name)
{
#ifndef STATIC_LINKING
vFP fp;
if (!name)
return NULL;
irc_dlsym(mod, name, fp);
if (fp)
return (fp);
return NULL;
#endif
}
vFP Module_Sym(char *name)
{
#ifndef STATIC_LINKING
vFP fp;
Module *mi;
if (!name)
return NULL;
/* Run through all modules and check for symbols */
for (mi = Modules; mi; mi = mi->next)
{
if (!(mi->flags & MODFLAG_TESTING) || (mi->flags & MODFLAG_DELAYED))
continue;
irc_dlsym(mi->dll, name, fp);
if (fp)
return (fp);
}
return NULL;
#endif
}
vFP Module_SymX(char *name, Module **mptr)
{
#ifndef STATIC_LINKING
vFP fp;
Module *mi;
if (!name)
return NULL;
/* Run through all modules and check for symbols */
for (mi = Modules; mi; mi = mi->next)
{
if (!(mi->flags & MODFLAG_TESTING) || (mi->flags & MODFLAG_DELAYED))
continue;
irc_dlsym(mi->dll, name, fp);
if (fp)
{
*mptr = mi;
return (fp);
}
}
*mptr = NULL;
return NULL;
#endif
}
void module_loadall(int module_load)
{
#ifndef STATIC_LINKING
iFP fp;
Module *mi, *next;
if (!loop.ircd_booted)
{
sendto_realops("Ehh, !loop.ircd_booted in module_loadall()");
return ;
}
/* Run through all modules and check for module load */
for (mi = Modules; mi; mi = next)
{
next = mi->next;
if (mi->flags & MODFLAG_LOADED)
continue;
irc_dlsym(mi->dll, "Mod_Load", fp);
/* Call the module_load */
if ((*fp)(module_load) != MOD_SUCCESS)
{
config_status("cannot load module %s", mi->header->name);
Module_free(mi);
}
else
mi->flags = MODFLAG_LOADED;
}
#endif
}
inline int Module_IsAlreadyChild(Module *parent, Module *child)
{
ModuleChild *mcp;
for (mcp = parent->children; mcp; mcp = mcp->next)
{
if (mcp->child == child)
return 1;
}
return 0;
}
inline void Module_AddAsChild(Module *parent, Module *child)
{
ModuleChild *childp = NULL;
childp = (ModuleChild *) MyMallocEx(sizeof(ModuleChild));
childp->child = child;
AddListItem(childp, parent->children);
}
int Module_Depend_Resolve(Module *p, char *path)
{
Mod_SymbolDepTable *d = p->header->symdep;
Module *parental = NULL;
if (d == NULL)
return 0;
#ifndef STATIC_LINKING
while (d->pointer)
{
if ((*(d->pointer) = Module_SymEx(p->dll, d->symbol)))
{
d++;
continue;
}
*(d->pointer) = Module_SymX(d->symbol, &parental);
if (!*(d->pointer))
{
/* If >= 3.2.3 */
if (p->mod_sys_version >= 0x32300)
{
char tmppath[PATH_MAX], curpath[PATH_MAX];
unreal_getpathname(path, curpath);
snprintf(tmppath, PATH_MAX, "%s/%s.%s", curpath, d->module,
MOD_EXTENSION);
config_progress("Unable to resolve symbol %s, attempting to load %s to find it", d->symbol, tmppath);
Module_Create(tmppath);
}
else
{
config_progress("Unable to resolve symbol %s, attempting to load %s to find it", d->symbol, d->module);
Module_Create(d->module);
}
*(d->pointer) = Module_SymX(d->symbol, &parental);
if (!*(d->pointer)) {
config_progress("module dependancy error: cannot resolve symbol %s",
d->symbol);
return -1;
}
}
if (!Module_IsAlreadyChild(parental, p))
Module_AddAsChild(parental, p);
d++;
}
return 0;
#else
while (d->pointer)
{
*((vFP *)d->pointer) = (vFP) d->realfunc;
d++;
}
#endif
}
/* m_module.
* by Stskeeps, codemastr, Syzop.
* Changed it so it's now public for users too, as quite some people
* (and users) requested they should have the right to see what kind
* of weird modules are loaded on the server, especially since people
* like to load spy modules these days.
* I do not consider this sensitive information, but just in case
* I stripped the version string for non-admins (eg: normal users). -- Syzop
*/
int m_module(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
Module *mi;
int i;
char tmp[1024], *p;
aCommand *mptr;
#ifdef DEBUGMODE
Efunction *e;
#endif
/* Opers can do /module <servername> */
if ((parc > 1) && (hunt_server_token(cptr, sptr, MSG_MODULE, TOK_MODULE, ":%s", 1, parc,
parv) != HUNTED_ISME))
return 0;
if (!Modules)
{
sendto_one(sptr, ":%s NOTICE %s :*** No modules loaded", me.name, sptr->name);
return 1;
}
for (mi = Modules; mi; mi = mi->next)
{
tmp[0] = '\0';
if (mi->flags & MODFLAG_DELAYED)
strcat(tmp, "[Unloading] ");
if (mi->options & MOD_OPT_PERM)
strcat(tmp, "[PERM] ");
if (!(mi->options & MOD_OPT_OFFICIAL))
strcat(tmp, "[3RD] ");
if (!IsOper(sptr))
sendto_one(sptr, ":%s NOTICE %s :*** %s (%s)%s", me.name, sptr->name,
mi->header->name, mi->header->description,
mi->options & MOD_OPT_OFFICIAL ? "" : " [3RD]");
else
sendto_one(sptr, ":%s NOTICE %s :*** %s - %s (%s) %s", me.name, sptr->name,
mi->header->name, mi->header->version, mi->header->description, tmp);
}
if (!IsOper(sptr))
return 0;
tmp[0] = '\0';
p = tmp;
for (i=0; i < MAXHOOKTYPES; i++)
{
if (!Hooks[i])
continue;
sprintf(p, "%d ", i);
p += strlen(p);
if (p > tmp+380)
{
sendto_one(sptr, ":%s NOTICE %s :Hooks: %s", me.name, sptr->name, tmp);
tmp[0] = '\0';
p = tmp;
}
}
sendto_one(sptr, ":%s NOTICE %s :Hooks: %s ", me.name, sptr->name, tmp);
tmp[0] = '\0';
p = tmp;
for (i=0; i < 256; i++)
{
for (mptr = CommandHash[i]; mptr; mptr = mptr->next)
if (mptr->overriders)
{
sprintf(p, "%s ", mptr->cmd);
p += strlen(p);
if (p > tmp+380)
{
sendto_one(sptr, ":%s NOTICE %s :Override: %s", me.name, sptr->name, tmp);
tmp[0] = '\0';
p = tmp;
}
}
}
sendto_one(sptr, ":%s NOTICE %s :Override: %s", me.name, sptr->name, tmp);
#ifdef DEBUGMODE
sendnotice(sptr, "Efunctions dump:");
for (i=0; i < MAXEFUNCTIONS; i++)
if ((e = Efunctions[i]))
{
sendnotice(sptr, "type=%d, name=%s, pointer=%p %s, owner=%s",
e->type,
efunction_table[e->type].name ? efunction_table[e->type].name : "<null>",
e->func.voidfunc,
*efunction_table[e->type].funcptr == e->func.voidfunc ? " [ACTIVE]" : "",
e->owner ? e->owner->header->name : "<null>");
}
#endif
return 1;
}
Hooktype *HooktypeFind(char *string) {
Hooktype *hooktype;
for (hooktype = Hooktypes; hooktype->string ;hooktype++) {
if (!stricmp(hooktype->string, string))
return hooktype;
}
return NULL;
}
Versionflag *VersionflagFind(char flag)
{
Versionflag *vflag;
for (vflag = Versionflags; vflag; vflag = vflag->next)
{
if (vflag->flag == flag)
return vflag;
}
return NULL;
}
Versionflag *VersionflagAdd(Module *module, char flag)
{
Versionflag *vflag;
ModuleChild *parent;
if ((vflag = VersionflagFind(flag)))
{
ModuleChild *child;
for (child = vflag->parents; child; child = child->next) {
if (child->child == module)
break;
}
if (!child)
{
parent = MyMallocEx(sizeof(ModuleChild));
parent->child = module;
if (module) {
ModuleObject *vflagobj;
vflagobj = MyMallocEx(sizeof(ModuleObject));
vflagobj->type = MOBJ_VERSIONFLAG;
vflagobj->object.versionflag = vflag;
AddListItem(vflagobj, module->objects);
module->errorcode = MODERR_NOERROR;
}
AddListItem(parent,vflag->parents);
}
return vflag;
}
vflag = MyMallocEx(sizeof(Versionflag));
vflag->flag = flag;
parent = MyMallocEx(sizeof(ModuleChild));
parent->child = module;
if (module)
{
ModuleObject *vflagobj;
vflagobj = MyMallocEx(sizeof(ModuleObject));
vflagobj->type = MOBJ_VERSIONFLAG;
vflagobj->object.versionflag = vflag;
AddListItem(vflagobj, module->objects);
module->errorcode = MODERR_NOERROR;
}
flag_add(flag);
AddListItem(parent,vflag->parents);
AddListItem(vflag, Versionflags);
return vflag;
}
void VersionflagDel(Versionflag *vflag, Module *module)
{
ModuleChild *owner;
if (!vflag)
return;
for (owner = vflag->parents; owner; owner = owner->next)
{
if (owner->child == module)
{
DelListItem(owner,vflag->parents);
MyFree(owner);
break;
}
}
if (module)
{
ModuleObject *objs;
for (objs = module->objects; objs; objs = objs->next) {
if (objs->type == MOBJ_VERSIONFLAG && objs->object.versionflag == vflag) {
DelListItem(objs,module->objects);
MyFree(objs);
break;
}
}
}
if (!vflag->parents)
{
flag_del(vflag->flag);
DelListItem(vflag, Versionflags);
MyFree(vflag);
}
}
Hooktype *HooktypeAdd(Module *module, char *string, int *type) {
Hooktype *hooktype;
int i;
ModuleChild *parent;
ModuleObject *hooktypeobj;
if ((hooktype = HooktypeFind(string))) {
ModuleChild *child;
for (child = hooktype->parents; child; child = child->next) {
if (child->child == module)
break;
}
if (!child) {
parent = MyMallocEx(sizeof(ModuleChild));
parent->child = module;
if (module) {
hooktypeobj = MyMallocEx(sizeof(ModuleObject));
hooktypeobj->type = MOBJ_HOOKTYPE;
hooktypeobj->object.hooktype = hooktype;
AddListItem(hooktypeobj, module->objects);
module->errorcode = MODERR_NOERROR;
}
AddListItem(parent,hooktype->parents);
}
*type = hooktype->id;
return hooktype;
}
for (hooktype = Hooktypes, i = 0; hooktype->string; hooktype++, i++) ;
if (i >= 39)
{
if (module)
module->errorcode = MODERR_NOSPACE;
return NULL;
}
Hooktypes[i].id = i+41;
Hooktypes[i].string = strdup(string);
parent = MyMallocEx(sizeof(ModuleChild));
parent->child = module;
if (module) {
hooktypeobj = MyMallocEx(sizeof(ModuleObject));
hooktypeobj->type = MOBJ_HOOKTYPE;
hooktypeobj->object.hooktype = &Hooktypes[i];
AddListItem(hooktypeobj,module->objects);
module->errorcode = MODERR_NOERROR;
}
AddListItem(parent,Hooktypes[i].parents);
*type = i+41;
return &Hooktypes[i];
}
void HooktypeDel(Hooktype *hooktype, Module *module) {
ModuleChild *child;
ModuleObject *objs;
for (child = hooktype->parents; child; child = child->next) {
if (child->child == module) {
DelListItem(child,hooktype->parents);
MyFree(child);
break;
}
}
if (module) {
for (objs = module->objects; objs; objs = objs->next) {
if (objs->type == MOBJ_HOOKTYPE && objs->object.hooktype == hooktype) {
DelListItem(objs,module->objects);
MyFree(objs);
break;
}
}
}
if (!hooktype->parents) {
MyFree(hooktype->string);
hooktype->string = NULL;
hooktype->id = 0;
hooktype->parents = NULL;
}
}
Hook *HookAddMain(Module *module, int hooktype, int (*func)(), void (*vfunc)(), char *(*cfunc)())
{
Hook *p;
p = (Hook *) MyMallocEx(sizeof(Hook));
if (func)
p->func.intfunc = func;
if (vfunc)
p->func.voidfunc = vfunc;
if (cfunc)
p->func.pcharfunc = cfunc;
p->type = hooktype;
p->owner = module;
AddListItem(p, Hooks[hooktype]);
if (module) {
ModuleObject *hookobj = (ModuleObject *)MyMallocEx(sizeof(ModuleObject));
hookobj->object.hook = p;
hookobj->type = MOBJ_HOOK;
AddListItem(hookobj, module->objects);
module->errorcode = MODERR_NOERROR;
}
return p;
}
Hook *HookDel(Hook *hook)
{
Hook *p, *q;
for (p = Hooks[hook->type]; p; p = p->next) {
if (p == hook) {
q = p->next;
DelListItem(p, Hooks[hook->type]);
if (p->owner) {
ModuleObject *hookobj;
for (hookobj = p->owner->objects; hookobj; hookobj = hookobj->next) {
if (hookobj->type == MOBJ_HOOK && hookobj->object.hook == p) {
DelListItem(hookobj, hook->owner->objects);
MyFree(hookobj);
break;
}
}
}
MyFree(p);
return q;
}
}
return NULL;
}
Callback *CallbackAddMain(Module *module, int cbtype, int (*func)(), void (*vfunc)(), char *(*cfunc)())
{
Callback *p;
p = (Callback *) MyMallocEx(sizeof(Callback));
if (func)
p->func.intfunc = func;
if (vfunc)
p->func.voidfunc = vfunc;
if (cfunc)
p->func.pcharfunc = cfunc;
p->type = cbtype;
p->owner = module;
AddListItem(p, Callbacks[cbtype]);
if (module) {
ModuleObject *cbobj = (ModuleObject *)MyMallocEx(sizeof(ModuleObject));
cbobj->object.callback = p;
cbobj->type = MOBJ_CALLBACK;
AddListItem(cbobj, module->objects);
module->errorcode = MODERR_NOERROR;
}
return p;
}
Callback *CallbackDel(Callback *cb)
{
Callback *p, *q;
for (p = Callbacks[cb->type]; p; p = p->next) {
if (p == cb) {
q = p->next;
DelListItem(p, Callbacks[cb->type]);
if (RCallbacks[cb->type] == p)
RCallbacks[cb->type] = NULL;
if (p->owner) {
ModuleObject *cbobj;
for (cbobj = p->owner->objects; cbobj; cbobj = cbobj->next) {
if ((cbobj->type == MOBJ_CALLBACK) && (cbobj->object.callback == p)) {
DelListItem(cbobj, cb->owner->objects);
MyFree(cbobj);
break;
}
}
}
MyFree(p);
return q;
}
}
return NULL;
}
Efunction *EfunctionAddMain(Module *module, int eftype, int (*func)(), void (*vfunc)(), void *(*pvfunc)(), char *(*cfunc)())
{
Efunction *p;
if (!module || !(module->options & MOD_OPT_OFFICIAL))
{
module->errorcode = MODERR_INVALID;
return NULL;
}
p = (Efunction *) MyMallocEx(sizeof(Efunction));
if (func)
p->func.intfunc = func;
if (vfunc)
p->func.voidfunc = vfunc;
if (pvfunc)
p->func.pvoidfunc = pvfunc;
if (cfunc)
p->func.pcharfunc = cfunc;
p->type = eftype;
p->owner = module;
AddListItem(p, Efunctions[eftype]);
if (module) {
ModuleObject *cbobj = (ModuleObject *)MyMallocEx(sizeof(ModuleObject));
cbobj->object.efunction = p;
cbobj->type = MOBJ_EFUNCTION;
AddListItem(cbobj, module->objects);
module->errorcode = MODERR_NOERROR;
}
return p;
}
Efunction *EfunctionDel(Efunction *cb)
{
Efunction *p, *q;
for (p = Efunctions[cb->type]; p; p = p->next) {
if (p == cb) {
q = p->next;
DelListItem(p, Efunctions[cb->type]);
if (*efunction_table[cb->type].funcptr == p)
*efunction_table[cb->type].funcptr = NULL;
if (p->owner) {
ModuleObject *cbobj;
for (cbobj = p->owner->objects; cbobj; cbobj = cbobj->next) {
if ((cbobj->type == MOBJ_EFUNCTION) && (cbobj->object.efunction == p)) {
DelListItem(cbobj, cb->owner->objects);
MyFree(cbobj);
break;
}
}
}
MyFree(p);
return q;
}
}
return NULL;
}
Cmdoverride *CmdoverrideAdd(Module *module, char *name, iFP function)
{
aCommand *p;
Cmdoverride *ovr;
if (!(p = find_Command_simple(name)))
{
if (module)
module->errorcode = MODERR_NOTFOUND;
return NULL;
}
for (ovr=p->overriders; ovr; ovr=ovr->next)
{
if ((ovr->owner == module) && (ovr->func == function))
{
if (module)
module->errorcode = MODERR_EXISTS;
return NULL;
}
}
ovr = MyMallocEx(sizeof(Cmdoverride));
ovr->func = function;
ovr->owner = module; /* TODO: module objects */
if (module)
{
ModuleObject *cmdoverobj = MyMallocEx(sizeof(ModuleObject));
cmdoverobj->type = MOBJ_CMDOVERRIDE;
cmdoverobj->object.cmdoverride = ovr;
AddListItem(cmdoverobj, module->objects);
module->errorcode = MODERR_NOERROR;
}
ovr->command = p;
if (!p->overriders)
p->overridetail = ovr;
AddListItem(ovr, p->overriders);
if (p->friend)
{
if (!p->friend->overriders)
p->friend->overridetail = ovr;
AddListItem(ovr, p->friend->overriders);
}
return ovr;
}
void CmdoverrideDel(Cmdoverride *cmd)
{
if (!cmd->next)
cmd->command->overridetail = cmd->prev;
DelListItem(cmd, cmd->command->overriders);
if (!cmd->command->overriders)
cmd->command->overridetail = NULL;
if (cmd->command->friend)
{
if (!cmd->prev)
cmd->command->friend->overridetail = NULL;
DelListItem(cmd, cmd->command->friend->overriders);
}
if (cmd->owner)
{
ModuleObject *obj;
for (obj = cmd->owner->objects; obj; obj = obj->next)
{
if (obj->type != MOBJ_CMDOVERRIDE)
continue;
if (obj->object.cmdoverride == cmd)
{
DelListItem(obj, cmd->owner->objects);
MyFree(obj);
break;
}
}
}
MyFree(cmd);
}
int CallCmdoverride(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[])
{
if (ovr->prev)
return ovr->prev->func(ovr->prev, cptr, sptr, parc, parv);
return ovr->command->func(cptr, sptr, parc, parv);
}
EVENT(e_unload_module_delayed)
{
char *name = strdup(data);
int i;
i = Module_Unload(name, 0);
if (i == -1)
{
sendto_realops("Failed to unload '%s'", name);
}
if (i == 1)
{
sendto_realops("Unloaded module %s", name);
}
free(name);
return;
}
void unload_all_modules(void)
{
Module *m;
int (*Mod_Unload)();
for (m = Modules; m; m = m->next)
{
irc_dlsym(m->dll, "Mod_Unload", Mod_Unload);
if (Mod_Unload)
(*Mod_Unload)(0);
remove(m->tmp_file);
}
}
unsigned int ModuleSetOptions(Module *module, unsigned int options)
{
unsigned int oldopts = module->options;
module->options = options;
return oldopts;
}
unsigned int ModuleGetOptions(Module *module)
{
return module->options;
}
unsigned int ModuleGetError(Module *module)
{
return module->errorcode;
}
static const char *module_error_str[] = {
"No error",
"Object already exists",
"No space available",
"Invalid parameter(s)",
"Object was not found"
};
const char *ModuleGetErrorStr(Module *module)
{
if (module->errorcode >= sizeof(module_error_str)/sizeof(module_error_str[0]))
return NULL;
return module_error_str[module->errorcode];
}
static int num_callbacks(int cbtype)
{
Callback *e;
int cnt = 0;
for (e = Callbacks[cbtype]; e; e = e->next)
if (!e->willberemoved)
cnt++;
return cnt;
}
/** Ensure that all required callbacks are in place and meet
* all specified requirements (eg: a cloaking module should
* be loaded).
*/
int callbacks_check(void)
{
int i;
if ((!num_callbacks(CALLBACKTYPE_CLOAK) && !num_callbacks(CALLBACKTYPE_CLOAK_EX)) || !num_callbacks(CALLBACKTYPE_CLOAKKEYCSUM))
{
#ifndef _WIN32
config_error("ERROR: No cloaking module loaded. (hint: you probably want to load cloak.so)");
#else
config_error("ERROR: No cloaking module loaded. (hint: you probably want to load modules\\cloak.dll)");
#endif
/* TEMPORARY! */
config_error("If you are upgrading from 3.2 (or any older version), be sure to read the release notes "
"or www.vulnscan.org/tmp/newcloak.txt regarding the cloaking change!");
return -1;
}
for (i=0; i < MAXCALLBACKS; i++)
{
if (num_callbacks(i) > 1)
{
config_error("ERROR: Multiple callbacks loaded for type %d. "
"Make sure you only load 1 module of 1 type (eg: only 1 cloaking module)",
i); /* TODO: make more clear? */
return -1;
}
}
return 0;
}
void callbacks_switchover(void)
{
Callback *e;
int i;
/* Now set the real callback, and tag the new one
* as 'willberemoved' if needed.
*/
for (i=0; i < MAXCALLBACKS; i++)
for (e = Callbacks[i]; e; e = e->next)
if (!e->willberemoved)
{
RCallbacks[i] = e; /* This is the new one. */
if (!(e->owner->options & MOD_OPT_PERM))
e->willberemoved = 1;
break;
}
}
static int num_efunctions(int eftype)
{
Efunction *e;
int cnt = 0;
#ifdef DEBUGMODE
if ((eftype < 0) || (eftype >= MAXEFUNCTIONS))
abort();
#endif
for (e = Efunctions[eftype]; e; e = e->next)
if (!e->willberemoved)
cnt++;
return cnt;
}
/** Ensure that all efunctions are present. */
int efunctions_check(void)
{
int i, n, errors=0;
for (i=0; i < MAXEFUNCTIONS; i++)
if (efunction_table[i].name)
{
n = num_efunctions(i);
if ((n != 1) && (errors > 10))
{
config_error("[--efunction errors truncated to prevent flooding--]");
break;
}
if (n < 1)
{
config_error("ERROR: efunction '%s' not found, you probably did not "
"load commands.so properly (or not all required m_* modules)",
efunction_table[i].name);
errors++;
} else
if (n > 1)
{
config_error("ERROR: efunction '%s' was found %d times, perhaps you "
"loaded commands.so twice or commands.so and a/the m_*.so module(s)",
efunction_table[i].name, n);
errors++;
}
}
return errors ? -1 : 0;
}
void efunctions_switchover(void)
{
Efunction *e;
int i;
/* Now set the real efunction, and tag the new one
* as 'willberemoved' if needed.
*/
for (i=0; i < MAXEFUNCTIONS; i++)
for (e = Efunctions[i]; e; e = e->next)
if (!e->willberemoved)
{
*efunction_table[i].funcptr = e->func.voidfunc; /* This is the new one. */
if (!(e->owner->options & MOD_OPT_PERM))
e->willberemoved = 1;
break;
}
}
#ifdef _WIN32
const char *our_dlerror(void)
{
static char errbuf[513];
DWORD err = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
0, errbuf, 512, NULL);
return errbuf;
}
#endif