]> jfr.im git - solanum.git/blobdiff - ircd/modules.c
Merge pull request #303 from edk0/modreload-uaf
[solanum.git] / ircd / modules.c
index 1d969af73e881e37bd506eb7b69f64ebd846844c..7a246cbe989b9fd09b200790caebbc3a7e6fb8d2 100644 (file)
@@ -36,6 +36,7 @@
 #include "match.h"
 #include "s_serv.h"
 #include "capability.h"
+#include "hash.h"
 
 #include <ltdl.h>
 
@@ -80,6 +81,29 @@ init_modules(void)
        mod_add_path(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]);
 }
 
+static unsigned int prev_caps;
+
+void
+mod_remember_clicaps(void)
+{
+       prev_caps = capability_index_mask(cli_capindex);
+}
+
+void
+mod_notify_clicaps(void)
+{
+       unsigned int cur_caps = capability_index_mask(cli_capindex);
+       unsigned int del = prev_caps & ~cur_caps;
+       unsigned int new = cur_caps & ~prev_caps;
+
+       if (del)
+               sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * DEL :%s",
+                               me.name, capability_index_list(cli_capindex, del));
+       if (new)
+               sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * NEW :%s",
+                               me.name, capability_index_list(cli_capindex, new));
+}
+
 /* mod_find_path()
  *
  * input       - path
@@ -294,9 +318,6 @@ unload_one_module(const char *name, bool warn)
        if((mod = findmodule_byname(name)) == NULL)
                return false;
 
-       if(mod->core)
-               return false;
-
        /*
         ** XXX - The type system in C does not allow direct conversion between
         ** data and function pointers, but as it happens, most C compilers will
@@ -385,10 +406,7 @@ unload_one_module(const char *name, bool warn)
                                        }
 
                                        if (m->cap_id != NULL)
-                                       {
                                                capability_orphan(idx, m->cap_name);
-                                               sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * DEL :%s", me.name, m->cap_name);
-                                       }
                                }
                        }
                        break;
@@ -431,7 +449,6 @@ load_a_module(const char *path, bool warn, int origin, bool core)
        lt_dlhandle tmpptr;
        char *mod_displayname, *c;
        const char *ver, *description = NULL;
-       size_t module_ext_len = strlen(LT_MODULE_EXT);
 
        int *mapi_version;
 
@@ -604,10 +621,7 @@ load_a_module(const char *path, bool warn, int origin, bool core)
 
                                        result = capability_put(idx, m->cap_name, m->cap_ownerdata);
                                        if (m->cap_id != NULL)
-                                       {
                                                *(m->cap_id) = result;
-                                               sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * ADD :%s", me.name, m->cap_name);
-                                       }
                                }
                        }
                }
@@ -668,3 +682,87 @@ load_a_module(const char *path, bool warn, int origin, bool core)
        rb_free(mod_displayname);
        return true;
 }
+
+void
+modules_do_reload(void *info_)
+{
+       struct modreload *info = info_;
+       struct module *mod;
+       int check_core;
+       int origin;
+       char *m_bn = rb_basename(info->module);
+       struct Client *source_p = find_id(info->id);
+
+       if((mod = findmodule_byname(m_bn)) == NULL)
+       {
+               if (source_p) sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
+               rb_free(info);
+               rb_free(m_bn);
+               return;
+       }
+
+       origin = mod->origin;
+       check_core = mod->core;
+
+       mod_remember_clicaps();
+
+       if(unload_one_module(m_bn, true) == false)
+       {
+               if (source_p) sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
+               rb_free(info);
+               rb_free(m_bn);
+               return;
+       }
+
+       if((load_one_module(m_bn, origin, check_core) == false) && check_core)
+       {
+               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                    "Error reloading core module: %s: terminating ircd", m_bn);
+               ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
+               exit(0);
+       }
+
+       mod_notify_clicaps();
+
+       rb_free(info);
+       rb_free(m_bn);
+}
+
+void
+modules_do_restart(void *unused)
+{
+       unsigned int modnum = 0;
+       rb_dlink_node *ptr, *nptr;
+
+       mod_remember_clicaps();
+
+       RB_DLINK_FOREACH_SAFE(ptr, nptr, module_list.head)
+       {
+               struct module *mod = ptr->data;
+               if(!unload_one_module(mod->name, false))
+               {
+                       ilog(L_MAIN, "Module Restart: %s was not unloaded %s",
+                            mod->name,
+                            mod->core? "(core module)" : "");
+
+                       if(!mod->core)
+                               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                                      "Module Restart: %s failed to unload",
+                                                      mod->name);
+                       continue;
+               }
+
+               modnum++;
+       }
+
+       load_all_modules(false);
+       load_core_modules(false);
+       rehash(false);
+
+       mod_notify_clicaps();
+
+       sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                            "Module Restart: %u modules unloaded, %lu modules loaded",
+                            modnum, rb_dlink_list_length(&module_list));
+       ilog(L_MAIN, "Module Restart: %u modules unloaded, %lu modules loaded", modnum, rb_dlink_list_length(&module_list));
+}