]> jfr.im git - solanum.git/blob - ircd/modules.c
strip_unprintable: clarify type conversion
[solanum.git] / ircd / modules.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * modules.c: A module loader.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 */
24
25 #include "stdinc.h"
26 #include "modules.h"
27 #include "logger.h"
28 #include "ircd.h"
29 #include "client.h"
30 #include "send.h"
31 #include "s_conf.h"
32 #include "s_newconf.h"
33 #include "numeric.h"
34 #include "parse.h"
35 #include "ircd_defs.h"
36 #include "match.h"
37 #include "s_serv.h"
38 #include "capability.h"
39
40 #include <ltdl.h>
41
42 #ifndef LT_MODULE_EXT
43 # error "Charybdis requires loadable module support."
44 #endif
45
46 rb_dlink_list module_list;
47 rb_dlink_list mod_paths;
48
49 static const char *core_module_table[] = {
50 "m_ban",
51 "m_die",
52 "m_error",
53 "m_join",
54 "m_kick",
55 "m_kill",
56 "m_message",
57 "m_mode",
58 "m_modules",
59 "m_nick",
60 "m_part",
61 "m_quit",
62 "m_server",
63 "m_squit",
64 NULL
65 };
66
67 #define MOD_WARN_DELTA (90 * 86400) /* time in seconds, 86400 seconds in a day */
68
69 void
70 init_modules(void)
71 {
72 if(lt_dlinit())
73 {
74 ilog(L_MAIN, "lt_dlinit failed");
75 exit(EXIT_FAILURE);
76 }
77
78 /* Add the default paths we look in to the module system --nenolod */
79 mod_add_path(ircd_paths[IRCD_PATH_MODULES]);
80 mod_add_path(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]);
81 }
82
83 static unsigned int prev_caps;
84
85 void
86 mod_remember_clicaps(void)
87 {
88 prev_caps = capability_index_mask(cli_capindex);
89 }
90
91 void
92 mod_notify_clicaps(void)
93 {
94 unsigned int cur_caps = capability_index_mask(cli_capindex);
95 unsigned int del = prev_caps & ~cur_caps;
96 unsigned int new = cur_caps & ~prev_caps;
97
98 if (del)
99 sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * DEL :%s",
100 me.name, capability_index_list(cli_capindex, del));
101 if (new)
102 sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * NEW :%s",
103 me.name, capability_index_list(cli_capindex, new));
104 }
105
106 /* mod_find_path()
107 *
108 * input - path
109 * output - none
110 * side effects - returns a module path from path
111 */
112 static char *
113 mod_find_path(const char *path)
114 {
115 rb_dlink_node *ptr;
116 char *mpath;
117
118 RB_DLINK_FOREACH(ptr, mod_paths.head)
119 {
120 mpath = ptr->data;
121
122 if(!strcmp(path, mpath))
123 return mpath;
124 }
125
126 return NULL;
127 }
128
129 /* mod_add_path
130 *
131 * input - path
132 * ouput -
133 * side effects - adds path to list
134 */
135 void
136 mod_add_path(const char *path)
137 {
138 char *pathst;
139
140 if(mod_find_path(path))
141 return;
142
143 pathst = rb_strdup(path);
144 rb_dlinkAddAlloc(pathst, &mod_paths);
145 }
146
147 /* mod_clear_paths()
148 *
149 * input -
150 * output -
151 * side effects - clear the lists of paths
152 */
153 void
154 mod_clear_paths(void)
155 {
156 rb_dlink_node *ptr, *next_ptr;
157
158 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
159 {
160 rb_free(ptr->data);
161 rb_free_rb_dlink_node(ptr);
162 }
163
164 mod_paths.head = mod_paths.tail = NULL;
165 mod_paths.length = 0;
166 }
167
168 /* findmodule_byname
169 *
170 * input - module to load
171 * output - index of module on success, -1 on failure
172 * side effects - none
173 */
174 struct module *
175 findmodule_byname(const char *name)
176 {
177 rb_dlink_node *ptr;
178 char name_ext[PATH_MAX + 1];
179
180 rb_strlcpy(name_ext, name, sizeof name_ext);
181 rb_strlcat(name_ext, LT_MODULE_EXT, sizeof name_ext);
182
183 RB_DLINK_FOREACH(ptr, module_list.head)
184 {
185 struct module *mod = ptr->data;
186
187 if(!irccmp(mod->name, name))
188 return mod;
189
190 if(!irccmp(mod->name, name_ext))
191 return mod;
192 }
193
194 return NULL;
195 }
196
197 /* load_all_modules()
198 *
199 * input -
200 * output -
201 * side effects -
202 */
203 void
204 load_all_modules(bool warn)
205 {
206 DIR *system_module_dir = NULL;
207 struct dirent *ldirent = NULL;
208 char module_fq_name[PATH_MAX + 1];
209 size_t module_ext_len = strlen(LT_MODULE_EXT);
210
211 system_module_dir = opendir(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]);
212
213 if(system_module_dir == NULL)
214 {
215 ilog(L_MAIN, "Could not load modules from %s: %s", ircd_paths[IRCD_PATH_AUTOLOAD_MODULES], strerror(errno));
216 return;
217 }
218
219 while ((ldirent = readdir(system_module_dir)) != NULL)
220 {
221 size_t len = strlen(ldirent->d_name);
222
223 if(len > module_ext_len &&
224 rb_strncasecmp(ldirent->d_name + (len - module_ext_len), LT_MODULE_EXT, module_ext_len) == 0)
225 {
226 (void) snprintf(module_fq_name, sizeof(module_fq_name), "%s%c%s",
227 ircd_paths[IRCD_PATH_AUTOLOAD_MODULES], RB_PATH_SEPARATOR, ldirent->d_name);
228 (void) load_a_module(module_fq_name, warn, MAPI_ORIGIN_CORE, false);
229 }
230
231 }
232 (void) closedir(system_module_dir);
233 }
234
235 /* load_core_modules()
236 *
237 * input -
238 * output -
239 * side effects - core modules are loaded, if any fail, kill ircd
240 */
241 void
242 load_core_modules(bool warn)
243 {
244 char module_name[PATH_MAX];
245 int i;
246
247
248 for (i = 0; core_module_table[i]; i++)
249 {
250 snprintf(module_name, sizeof(module_name), "%s%c%s", ircd_paths[IRCD_PATH_MODULES], RB_PATH_SEPARATOR,
251 core_module_table[i]);
252
253 if(load_a_module(module_name, warn, MAPI_ORIGIN_CORE, true) == false)
254 {
255 ilog(L_MAIN,
256 "Error loading core module %s: terminating ircd",
257 core_module_table[i]);
258 exit(EXIT_FAILURE);
259 }
260 }
261 }
262
263 /* load_one_module()
264 *
265 * input -
266 * output -
267 * side effects -
268 */
269 bool
270 load_one_module(const char *path, int origin, bool coremodule)
271 {
272 char modpath[PATH_MAX];
273 rb_dlink_node *pathst;
274
275 if (server_state_foreground)
276 inotice("loading module %s ...", path);
277
278 if(coremodule)
279 origin = MAPI_ORIGIN_CORE;
280
281 RB_DLINK_FOREACH(pathst, mod_paths.head)
282 {
283 struct stat statbuf;
284 const char *mpath = pathst->data;
285
286 snprintf(modpath, sizeof(modpath), "%s%c%s%s", mpath, RB_PATH_SEPARATOR, path, LT_MODULE_EXT);
287 if((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
288 {
289 if(stat(modpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
290 {
291 /* Regular files only please */
292 return load_a_module(modpath, true, origin, coremodule);
293 }
294
295 }
296 }
297
298 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
299 return false;
300 }
301
302 static char unknown_ver[] = "<unknown>";
303 static char unknown_description[] = "<none>";
304
305 /* unload_one_module()
306 *
307 * inputs - name of module to unload
308 * - true to say modules unloaded, false to not
309 * output - true if successful, false if error
310 * side effects - module is unloaded
311 */
312 bool
313 unload_one_module(const char *name, bool warn)
314 {
315 struct module *mod;
316
317 if((mod = findmodule_byname(name)) == NULL)
318 return false;
319
320 /*
321 ** XXX - The type system in C does not allow direct conversion between
322 ** data and function pointers, but as it happens, most C compilers will
323 ** safely do this, however it is a theoretical overlow to cast as we
324 ** must do here. I have library functions to take care of this, but
325 ** despite being more "correct" for the C language, this is more
326 ** practical. Removing the abuse of the ability to cast ANY pointer
327 ** to and from an integer value here will break some compilers.
328 ** -jmallett
329 */
330 /* Left the comment in but the code isn't here any more -larne */
331 switch (mod->mapi_version)
332 {
333 case 1:
334 {
335 struct mapi_mheader_av1 *mheader = mod->mapi_header;
336 if(mheader->mapi_command_list)
337 {
338 struct Message **m;
339 for (m = mheader->mapi_command_list; *m; ++m)
340 mod_del_cmd(*m);
341 }
342
343 /* hook events are never removed, we simply lose the
344 * ability to call them --fl
345 */
346 if(mheader->mapi_hfn_list)
347 {
348 mapi_hfn_list_av1 *m;
349 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
350 remove_hook(m->hapi_name, m->fn);
351 }
352
353 if(mheader->mapi_unregister)
354 mheader->mapi_unregister();
355 break;
356 }
357 case 2:
358 {
359 struct mapi_mheader_av2 *mheader = mod->mapi_header;
360
361 /* XXX duplicate code :( */
362 if(mheader->mapi_command_list)
363 {
364 struct Message **m;
365 for (m = mheader->mapi_command_list; *m; ++m)
366 mod_del_cmd(*m);
367 }
368
369 /* hook events are never removed, we simply lose the
370 * ability to call them --fl
371 */
372 if(mheader->mapi_hfn_list)
373 {
374 mapi_hfn_list_av1 *m;
375 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
376 remove_hook(m->hapi_name, m->fn);
377 }
378
379 if(mheader->mapi_unregister)
380 mheader->mapi_unregister();
381
382 if(mheader->mapi_cap_list)
383 {
384 mapi_cap_list_av2 *m;
385 for (m = mheader->mapi_cap_list; m->cap_name; ++m)
386 {
387 struct CapabilityIndex *idx;
388
389 switch (m->cap_index)
390 {
391 case MAPI_CAP_CLIENT:
392 idx = cli_capindex;
393 break;
394 case MAPI_CAP_SERVER:
395 idx = serv_capindex;
396 break;
397 default:
398 sendto_realops_snomask(SNO_GENERAL, L_ALL,
399 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
400 m->cap_index, m->cap_name, mod->name);
401 ilog(L_MAIN,
402 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
403 m->cap_index, m->cap_name, mod->name);
404 continue;
405 }
406
407 if (m->cap_id != NULL)
408 capability_orphan(idx, m->cap_name);
409 }
410 }
411 break;
412 }
413 default:
414 sendto_realops_snomask(SNO_GENERAL, L_ALL,
415 "Unknown/unsupported MAPI version %d when unloading %s!",
416 mod->mapi_version, mod->name);
417 ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
418 mod->mapi_version, mod->name);
419 break;
420 }
421
422 lt_dlclose(mod->address);
423
424 rb_dlinkDelete(&mod->node, &module_list);
425 rb_free(mod->name);
426 rb_free(mod);
427
428 if(warn)
429 {
430 ilog(L_MAIN, "Module %s unloaded", name);
431 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
432 }
433
434 return true;
435 }
436
437 /*
438 * load_a_module()
439 *
440 * inputs - path name of module, bool to notice, int of origin, bool if core
441 * output - false if error true if success
442 * side effects - loads a module if successful
443 */
444 bool
445 load_a_module(const char *path, bool warn, int origin, bool core)
446 {
447 struct module *mod;
448 lt_dlhandle tmpptr;
449 char *mod_displayname, *c;
450 const char *ver, *description = NULL;
451
452 int *mapi_version;
453
454 mod_displayname = rb_basename(path);
455
456 /* Trim off the ending for the display name if we have to */
457 if((c = rb_strcasestr(mod_displayname, LT_MODULE_EXT)) != NULL)
458 *c = '\0';
459
460 tmpptr = lt_dlopenext(path);
461
462 if(tmpptr == NULL)
463 {
464 const char *err = lt_dlerror();
465
466 sendto_realops_snomask(SNO_GENERAL, L_ALL,
467 "Error loading module %s: %s", mod_displayname, err);
468 ilog(L_MAIN, "Error loading module %s: %s", mod_displayname, err);
469 rb_free(mod_displayname);
470 return false;
471 }
472
473 /*
474 * _mheader is actually a struct mapi_mheader_*, but mapi_version
475 * is always the first member of this structure, so we treate it
476 * as a single int in order to determine the API version.
477 * -larne.
478 */
479 mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "_mheader");
480 if((mapi_version == NULL
481 && (mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "__mheader")) == NULL)
482 || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
483 {
484 sendto_realops_snomask(SNO_GENERAL, L_ALL,
485 "Data format error: module %s has no MAPI header.",
486 mod_displayname);
487 ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_displayname);
488 (void) lt_dlclose(tmpptr);
489 rb_free(mod_displayname);
490 return false;
491 }
492
493 switch (MAPI_VERSION(*mapi_version))
494 {
495 case 1:
496 {
497 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *)(void *)mapi_version; /* see above */
498 if(mheader->mapi_register && (mheader->mapi_register() == -1))
499 {
500 ilog(L_MAIN, "Module %s indicated failure during load.",
501 mod_displayname);
502 sendto_realops_snomask(SNO_GENERAL, L_ALL,
503 "Module %s indicated failure during load.",
504 mod_displayname);
505 lt_dlclose(tmpptr);
506 rb_free(mod_displayname);
507 return false;
508 }
509 if(mheader->mapi_command_list)
510 {
511 struct Message **m;
512 for (m = mheader->mapi_command_list; *m; ++m)
513 mod_add_cmd(*m);
514 }
515
516 if(mheader->mapi_hook_list)
517 {
518 mapi_hlist_av1 *m;
519 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
520 *m->hapi_id = register_hook(m->hapi_name);
521 }
522
523 if(mheader->mapi_hfn_list)
524 {
525 mapi_hfn_list_av1 *m;
526 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
527 add_hook(m->hapi_name, m->fn);
528 }
529
530 ver = mheader->mapi_module_version;
531 break;
532 }
533 case 2:
534 {
535 struct mapi_mheader_av2 *mheader = (struct mapi_mheader_av2 *)(void *)mapi_version; /* see above */
536
537 /* XXX duplicated code :( */
538 if(mheader->mapi_register && (mheader->mapi_register() == -1))
539 {
540 ilog(L_MAIN, "Module %s indicated failure during load.",
541 mod_displayname);
542 sendto_realops_snomask(SNO_GENERAL, L_ALL,
543 "Module %s indicated failure during load.",
544 mod_displayname);
545 lt_dlclose(tmpptr);
546 rb_free(mod_displayname);
547 return false;
548 }
549
550 /* Basic date code checks
551 *
552 * Don't make them fatal, but do complain about differences within a certain time frame.
553 * Later on if there are major API changes we can add fatal checks.
554 * -- Elizafox
555 */
556 if(mheader->mapi_datecode != datecode && mheader->mapi_datecode > 0)
557 {
558 long int delta = datecode - mheader->mapi_datecode;
559 if (delta > MOD_WARN_DELTA)
560 {
561 delta /= 86400;
562 iwarn("Module %s build date is out of sync with ircd build date by %ld days, expect problems",
563 mod_displayname, delta);
564 sendto_realops_snomask(SNO_GENERAL, L_ALL,
565 "Module %s build date is out of sync with ircd build date by %ld days, expect problems",
566 mod_displayname, delta);
567 }
568 }
569
570 if(mheader->mapi_command_list)
571 {
572 struct Message **m;
573 for (m = mheader->mapi_command_list; *m; ++m)
574 mod_add_cmd(*m);
575 }
576
577 if(mheader->mapi_hook_list)
578 {
579 mapi_hlist_av1 *m;
580 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
581 *m->hapi_id = register_hook(m->hapi_name);
582 }
583
584 if(mheader->mapi_hfn_list)
585 {
586 mapi_hfn_list_av1 *m;
587 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
588 add_hook(m->hapi_name, m->fn);
589 }
590
591 /* New in MAPI v2 - version replacement */
592 ver = mheader->mapi_module_version ? mheader->mapi_module_version : ircd_version;
593 description = mheader->mapi_module_description;
594
595 if(mheader->mapi_cap_list)
596 {
597 mapi_cap_list_av2 *m;
598 for (m = mheader->mapi_cap_list; m->cap_name; ++m)
599 {
600 struct CapabilityIndex *idx;
601 int result;
602
603 switch (m->cap_index)
604 {
605 case MAPI_CAP_CLIENT:
606 idx = cli_capindex;
607 break;
608 case MAPI_CAP_SERVER:
609 idx = serv_capindex;
610 break;
611 default:
612 sendto_realops_snomask(SNO_GENERAL, L_ALL,
613 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
614 m->cap_index, m->cap_name, mod_displayname);
615 ilog(L_MAIN,
616 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
617 m->cap_index, m->cap_name, mod_displayname);
618 continue;
619 }
620
621 result = capability_put(idx, m->cap_name, m->cap_ownerdata);
622 if (m->cap_id != NULL)
623 *(m->cap_id) = result;
624 }
625 }
626 }
627
628 break;
629 default:
630 ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
631 mod_displayname, MAPI_VERSION(*mapi_version));
632 sendto_realops_snomask(SNO_GENERAL, L_ALL,
633 "Module %s has unknown/unsupported MAPI version %d.",
634 mod_displayname, *mapi_version);
635 lt_dlclose(tmpptr);
636 rb_free(mod_displayname);
637 return false;
638 }
639
640 if(ver == NULL)
641 ver = unknown_ver;
642
643 if(description == NULL)
644 description = unknown_description;
645
646 mod = rb_malloc(sizeof(struct module));
647 mod->address = tmpptr;
648 mod->version = ver;
649 mod->description = description;
650 mod->core = core;
651 mod->name = rb_strdup(mod_displayname);
652 mod->mapi_header = mapi_version;
653 mod->mapi_version = MAPI_VERSION(*mapi_version);
654 mod->origin = origin;
655 rb_dlinkAdd(mod, &mod->node, &module_list);
656
657 if(warn)
658 {
659 const char *o;
660
661 switch (origin)
662 {
663 case MAPI_ORIGIN_EXTENSION:
664 o = "extension";
665 break;
666 case MAPI_ORIGIN_CORE:
667 o = "core";
668 break;
669 default:
670 o = "unknown";
671 break;
672 }
673
674 sendto_realops_snomask(SNO_GENERAL, L_ALL,
675 "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
676 mod_displayname, ver, MAPI_VERSION(*mapi_version), o, description,
677 (void *) tmpptr);
678 ilog(L_MAIN, "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
679 mod_displayname, ver, MAPI_VERSION(*mapi_version), o, description, (void *) tmpptr);
680 }
681 rb_free(mod_displayname);
682 return true;
683 }
684
685 void
686 modules_do_restart(void *unused)
687 {
688 unsigned int modnum = 0;
689 rb_dlink_node *ptr, *nptr;
690
691 mod_remember_clicaps();
692
693 RB_DLINK_FOREACH_SAFE(ptr, nptr, module_list.head)
694 {
695 struct module *mod = ptr->data;
696 if(!unload_one_module(mod->name, false))
697 {
698 ilog(L_MAIN, "Module Restart: %s was not unloaded %s",
699 mod->name,
700 mod->core? "(core module)" : "");
701
702 if(!mod->core)
703 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
704 "Module Restart: %s failed to unload",
705 mod->name);
706 continue;
707 }
708
709 modnum++;
710 }
711
712 load_all_modules(false);
713 load_core_modules(false);
714 rehash(false);
715
716 mod_notify_clicaps();
717
718 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
719 "Module Restart: %u modules unloaded, %lu modules loaded",
720 modnum, rb_dlink_list_length(&module_list));
721 ilog(L_MAIN, "Module Restart: %u modules unloaded, %lu modules loaded", modnum, rb_dlink_list_length(&module_list));
722 }