Add new flag MOD_OPT_PERM_RELOADABLE. Can be used instead of MOD_OPT_PERM if

you want to permit re-loading but not complete un-loading of your module.
This way you get the benefits of being able to upgrade code on-the-fly but
can still disallow the user to do something potentially unwise.
This commit is contained in:
Bram Matthys 2015-05-23 20:43:31 +02:00
parent 1e8c2c0141
commit c2ca896dea
8 changed files with 44 additions and 5 deletions

View file

@ -492,6 +492,7 @@ struct _Module
#define MOD_OPT_PERM 0x0001 /* Permanent module (not unloadable) */
#define MOD_OPT_OFFICIAL 0x0002 /* Official module, do not set "tainted" */
#define MOD_OPT_PERM_RELOADABLE 0x0004 /* Module is semi-permanent: it can be re-loaded but not un-loaded */
struct _mod_symboltable
{

View file

@ -983,6 +983,8 @@ int m_module(aClient *cptr, aClient *sptr, int parc, char *parv[])
tmp[0] = '\0';
if (mi->flags & MODFLAG_DELAYED)
strncat(tmp, "[Unloading] ", sizeof(tmp)-strlen(tmp)-1);
if (mi->options & MOD_OPT_PERM_RELOADABLE)
strncat(tmp, "[PERM-BUT-RELOADABLE] ", sizeof(tmp)-strlen(tmp)-1);
if (mi->options & MOD_OPT_PERM)
strncat(tmp, "[PERM] ", sizeof(tmp)-strlen(tmp)-1);
if (!(mi->options & MOD_OPT_OFFICIAL))

View file

@ -120,7 +120,7 @@ DLLFUNC int MOD_INIT(floodprot)(ModuleInfo *modinfo)
ModDataInfo mreq;
MARK_AS_OFFICIAL_MODULE(modinfo);
ModuleSetOptions(modinfo->handle,MOD_OPT_PERM,1);
ModuleSetOptions(modinfo->handle,MOD_OPT_PERM_RELOADABLE,1);
ModInfo = modinfo;
memset(&creq, 0, sizeof(creq));

View file

@ -64,7 +64,7 @@ aJFlood *cmodej_addentry(aClient *cptr, aChannel *chptr);
DLLFUNC int MOD_INIT(jointhrottle)(ModuleInfo *modinfo)
{
CmodeInfo req;
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM, 1);
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM_RELOADABLE, 1);
MARK_AS_OFFICIAL_MODULE(modinfo);
ModInfo = modinfo;
memset(&req, 0, sizeof(req));

View file

@ -54,7 +54,7 @@ int link_can_join_limitexceeded(aClient *sptr, aChannel *chptr, char *key, char
DLLFUNC int MOD_INIT(link)(ModuleInfo *modinfo)
{
CmodeInfo req;
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM, 1);
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM_RELOADABLE, 1);
MARK_AS_OFFICIAL_MODULE(modinfo);
memset(&req, 0, sizeof(req));
req.paracount = 1;

View file

@ -67,7 +67,7 @@ DLLFUNC int MOD_INIT(m_dummy)(ModuleInfo *modinfo)
{
CmodeInfo req;
ircd_log(LOG_ERROR, "debug: mod_init called from chmodetst module");
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM);
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM_RELOADABLE); /* Cannot be unloaded but can be re-loaded */
sendto_realops("chmodetst loading...");
/* TODO: load mode here */
/* +w doesn't do anything, it's just for testing */

View file

@ -41,6 +41,9 @@ DLLFUNC int MOD_INIT(ssl_antidos)(ModuleInfo *modinfo)
HookAddEx(modinfo->handle, HOOKTYPE_HANDSHAKE, ssl_antidos_handshake);
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM, 1);
/* Note that we cannot be MOD_OPT_PERM_RELOADABLE as we use OpenSSL functions to register
* an index and callback function.
*/
ssl_antidos_index = SSL_get_ex_new_index(0, "ssl_antidos", NULL, NULL, ssl_antidos_free);

View file

@ -327,6 +327,7 @@ extern void charsys_add_language(char *name);
extern void charsys_reset_pretest(void);
int charsys_postconftest(void);
void charsys_finish(void);
int reloadable_perm_module_unloaded(void);
void delete_cgiircblock(ConfigItem_cgiirc *e);
/*
@ -1652,7 +1653,7 @@ int init_conf(char *rootconf, int rehash)
{
charsys_reset_pretest();
if ((config_test() < 0) || (callbacks_check() < 0) || (efunctions_check() < 0) ||
(charsys_postconftest() < 0) || ssl_used_in_config_but_unavail())
(charsys_postconftest() < 0) || ssl_used_in_config_but_unavail() || reloadable_perm_module_unloaded())
{
config_error("IRCd configuration failed to pass testing");
#ifdef _WIN32
@ -9695,3 +9696,35 @@ int ssl_used_in_config_but_unavail(void)
return (errors ? 1 : 0);
}
/** Check if the user attempts to unload (eg: by commenting out) a module
* that is currently loaded and is tagged as MOD_OPT_PERM_RELOADABLE
* (in other words: a module that allows re-loading but not un-loading)
*/
int reloadable_perm_module_unloaded(void)
{
Module *m, *m2;
extern Module *Modules;
int ret = 0;
for (m = Modules; m; m = m->next)
{
if ((m->options & MOD_OPT_PERM_RELOADABLE) && (m->flags & MODFLAG_LOADED))
{
/* For each module w/MOD_OPT_PERM_RELOADABLE that is currently fully loaded... */
int found = 0;
for (m2 = Modules; m2; m2 = m2->next)
{
if ((m != m2) && !strcmp(m->header->name, m2->header->name))
found = 1;
}
if (!found)
{
config_error("Attempt to unload module '%s' is not permitted. Module is permanent and reloadable only.", m->header->name);
ret = 1;
/* we don't return straight away so the user gets to see all errors and not just one */
}
}
}
return ret;
}