]> jfr.im git - solanum.git/blob - ircd/modules.c
librb: add versions of rb_strcasecmp, rb_strncasecmp, and rb_strcasestr.
[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 struct module **modlist = NULL;
47
48 static const char *core_module_table[] = {
49 "m_ban",
50 "m_die",
51 "m_error",
52 "m_join",
53 "m_kick",
54 "m_kill",
55 "m_message",
56 "m_mode",
57 "m_nick",
58 "m_part",
59 "m_quit",
60 "m_server",
61 "m_squit",
62 NULL
63 };
64
65 #define MOD_WARN_DELTA (90 * 86400) /* time in seconds, 86400 seconds in a day */
66
67 #define MODS_INCREMENT 10
68 int num_mods = 0;
69 int max_mods = MODS_INCREMENT;
70
71 static rb_dlink_list mod_paths;
72
73 static void mo_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
74 static void mo_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
75 static void mo_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
76 static void mo_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
77 static void mo_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
78
79 static void me_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
80 static void me_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
81 static void me_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
82 static void me_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
83 static void me_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
84
85 static void do_modload(struct Client *, const char *);
86 static void do_modunload(struct Client *, const char *);
87 static void do_modreload(struct Client *, const char *);
88 static void do_modlist(struct Client *, const char *);
89 static void do_modrestart(struct Client *);
90
91 struct Message modload_msgtab = {
92 "MODLOAD", 0, 0, 0, 0,
93 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
94 };
95
96 struct Message modunload_msgtab = {
97 "MODUNLOAD", 0, 0, 0, 0,
98 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modunload, 2}, {mo_modunload, 2}}
99 };
100
101 struct Message modreload_msgtab = {
102 "MODRELOAD", 0, 0, 0, 0,
103 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modreload, 2}, {mo_modreload, 2}}
104 };
105
106 struct Message modlist_msgtab = {
107 "MODLIST", 0, 0, 0, 0,
108 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modlist, 0}, {mo_modlist, 0}}
109 };
110
111 struct Message modrestart_msgtab = {
112 "MODRESTART", 0, 0, 0, 0,
113 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0}}
114 };
115
116 void
117 modules_init(void)
118 {
119 if(lt_dlinit())
120 {
121 ilog(L_MAIN, "lt_dlinit failed");
122 exit(0);
123 }
124
125 mod_add_cmd(&modload_msgtab);
126 mod_add_cmd(&modunload_msgtab);
127 mod_add_cmd(&modreload_msgtab);
128 mod_add_cmd(&modlist_msgtab);
129 mod_add_cmd(&modrestart_msgtab);
130
131 /* Add the default paths we look in to the module system --nenolod */
132 mod_add_path(ircd_paths[IRCD_PATH_MODULES]);
133 mod_add_path(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]);
134 }
135
136 /* mod_find_path()
137 *
138 * input - path
139 * output - none
140 * side effects - returns a module path from path
141 */
142 static char *
143 mod_find_path(const char *path)
144 {
145 rb_dlink_node *ptr;
146 char *mpath;
147
148 RB_DLINK_FOREACH(ptr, mod_paths.head)
149 {
150 mpath = ptr->data;
151
152 if(!strcmp(path, mpath))
153 return mpath;
154 }
155
156 return NULL;
157 }
158
159 /* mod_add_path
160 *
161 * input - path
162 * ouput -
163 * side effects - adds path to list
164 */
165 void
166 mod_add_path(const char *path)
167 {
168 char *pathst;
169
170 if(mod_find_path(path))
171 return;
172
173 pathst = rb_strdup(path);
174 rb_dlinkAddAlloc(pathst, &mod_paths);
175 }
176
177 /* mod_clear_paths()
178 *
179 * input -
180 * output -
181 * side effects - clear the lists of paths
182 */
183 void
184 mod_clear_paths(void)
185 {
186 rb_dlink_node *ptr, *next_ptr;
187
188 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
189 {
190 rb_free(ptr->data);
191 rb_free_rb_dlink_node(ptr);
192 }
193
194 mod_paths.head = mod_paths.tail = NULL;
195 mod_paths.length = 0;
196 }
197
198 /* findmodule_byname
199 *
200 * input - module to load
201 * output - index of module on success, -1 on failure
202 * side effects - none
203 */
204 int
205 findmodule_byname(const char *name)
206 {
207 int i;
208 char name_ext[PATH_MAX + 1];
209
210 rb_strlcpy(name_ext, name, sizeof name_ext);
211 rb_strlcat(name_ext, LT_MODULE_EXT, sizeof name_ext);
212
213 for (i = 0; i < num_mods; i++)
214 {
215 if(!irccmp(modlist[i]->name, name))
216 return i;
217
218 if(!irccmp(modlist[i]->name, name_ext))
219 return i;
220 }
221
222 return -1;
223 }
224
225 /* load_all_modules()
226 *
227 * input -
228 * output -
229 * side effects -
230 */
231 void
232 load_all_modules(bool warn)
233 {
234 DIR *system_module_dir = NULL;
235 struct dirent *ldirent = NULL;
236 char module_fq_name[PATH_MAX + 1];
237 size_t module_ext_len = strlen(LT_MODULE_EXT);
238
239 modules_init();
240
241 modlist = (struct module **) rb_malloc(sizeof(struct module *) * (MODS_INCREMENT));
242
243 max_mods = MODS_INCREMENT;
244
245 system_module_dir = opendir(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]);
246
247 if(system_module_dir == NULL)
248 {
249 ilog(L_MAIN, "Could not load modules from %s: %s", ircd_paths[IRCD_PATH_AUTOLOAD_MODULES], strerror(errno));
250 return;
251 }
252
253 while ((ldirent = readdir(system_module_dir)) != NULL)
254 {
255 size_t len = strlen(ldirent->d_name);
256
257 if(len > module_ext_len &&
258 strncasecmp(ldirent->d_name + (len - module_ext_len), LT_MODULE_EXT, module_ext_len) == 0)
259 {
260 (void) snprintf(module_fq_name, sizeof(module_fq_name), "%s%c%s",
261 ircd_paths[IRCD_PATH_AUTOLOAD_MODULES], RB_PATH_SEPARATOR, ldirent->d_name);
262 (void) load_a_module(module_fq_name, warn, MAPI_ORIGIN_CORE, false);
263 }
264
265 }
266 (void) closedir(system_module_dir);
267 }
268
269 /* load_core_modules()
270 *
271 * input -
272 * output -
273 * side effects - core modules are loaded, if any fail, kill ircd
274 */
275 void
276 load_core_modules(bool warn)
277 {
278 char module_name[PATH_MAX];
279 int i;
280
281
282 for (i = 0; core_module_table[i]; i++)
283 {
284 snprintf(module_name, sizeof(module_name), "%s%c%s", ircd_paths[IRCD_PATH_MODULES], RB_PATH_SEPARATOR,
285 core_module_table[i]);
286
287 if(load_a_module(module_name, warn, MAPI_ORIGIN_CORE, true) == false)
288 {
289 ilog(L_MAIN,
290 "Error loading core module %s: terminating ircd",
291 core_module_table[i]);
292 exit(0);
293 }
294 }
295 }
296
297 /* load_one_module()
298 *
299 * input -
300 * output -
301 * side effects -
302 */
303 bool
304 load_one_module(const char *path, int origin, bool coremodule)
305 {
306 char modpath[PATH_MAX];
307 rb_dlink_node *pathst;
308
309 if (server_state_foreground)
310 inotice("loading module %s ...", path);
311
312 if(coremodule)
313 origin = MAPI_ORIGIN_CORE;
314
315 RB_DLINK_FOREACH(pathst, mod_paths.head)
316 {
317 struct stat statbuf;
318 const char *mpath = pathst->data;
319
320 snprintf(modpath, sizeof(modpath), "%s%c%s%s", mpath, RB_PATH_SEPARATOR, path, LT_MODULE_EXT);
321 if((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
322 {
323 if(stat(modpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
324 {
325 /* Regular files only please */
326 return load_a_module(modpath, true, origin, coremodule);
327 }
328
329 }
330 }
331
332 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
333 return false;
334 }
335
336
337 /* load a module .. */
338 static void
339 mo_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
340 {
341 if(!IsOperAdmin(source_p))
342 {
343 sendto_one(source_p, form_str(ERR_NOPRIVS),
344 me.name, source_p->name, "admin");
345 return;
346 }
347
348 if(parc > 2)
349 {
350 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
351 "ENCAP %s MODLOAD %s", parv[2], parv[1]);
352 if(match(parv[2], me.name) == 0)
353 return;
354 }
355
356 do_modload(source_p, parv[1]);
357 }
358
359 static void
360 me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
361 {
362 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
363 {
364 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
365 "to load modules on this server.");
366 return;
367 }
368
369 do_modload(source_p, parv[1]);
370 }
371
372
373 /* unload a module .. */
374 static void
375 mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
376 {
377 if(!IsOperAdmin(source_p))
378 {
379 sendto_one(source_p, form_str(ERR_NOPRIVS),
380 me.name, source_p->name, "admin");
381 return;
382 }
383
384 if(parc > 2)
385 {
386 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
387 "ENCAP %s MODUNLOAD %s", parv[2], parv[1]);
388 if(match(parv[2], me.name) == 0)
389 return;
390 }
391
392 do_modunload(source_p, parv[1]);
393 }
394
395 static void
396 me_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
397 {
398 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
399 {
400 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
401 "to load modules on this server.");
402 return;
403 }
404
405 do_modunload(source_p, parv[1]);
406 }
407
408 /* unload and load in one! */
409 static void
410 mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
411 {
412 if(!IsOperAdmin(source_p))
413 {
414 sendto_one(source_p, form_str(ERR_NOPRIVS),
415 me.name, source_p->name, "admin");
416 return;
417 }
418
419 if(parc > 2)
420 {
421 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
422 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
423 if(match(parv[2], me.name) == 0)
424 return;
425 }
426
427 do_modreload(source_p, parv[1]);
428 }
429
430 static void
431 me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
432 {
433 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
434 {
435 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
436 "to load modules on this server.");
437 return;
438 }
439
440 do_modreload(source_p, parv[1]);
441 }
442
443 /* list modules .. */
444 static void
445 mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
446 {
447 if(!IsOperAdmin(source_p))
448 {
449 sendto_one(source_p, form_str(ERR_NOPRIVS),
450 me.name, source_p->name, "admin");
451 return;
452 }
453
454 if(parc > 2)
455 {
456 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
457 "ENCAP %s MODLIST %s", parv[2], parv[1]);
458 if(match(parv[2], me.name) == 0)
459 return;
460 }
461
462 do_modlist(source_p, parc > 1 ? parv[1] : 0);
463 }
464
465 static void
466 me_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
467 {
468 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
469 {
470 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
471 "to load modules on this server.");
472 return;
473 }
474
475 do_modlist(source_p, parv[1]);
476 }
477
478 /* unload and reload all modules */
479 static void
480 mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
481 {
482 if(!IsOperAdmin(source_p))
483 {
484 sendto_one(source_p, form_str(ERR_NOPRIVS),
485 me.name, source_p->name, "admin");
486 return;
487 }
488
489 if(parc > 1)
490 {
491 sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
492 "ENCAP %s MODRESTART", parv[1]);
493 if(match(parv[1], me.name) == 0)
494 return;
495 }
496
497 do_modrestart(source_p);
498 }
499
500 static void
501 me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
502 {
503 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
504 {
505 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
506 "to load modules on this server.");
507 return;
508 }
509
510 do_modrestart(source_p);
511 }
512
513 static void
514 do_modload(struct Client *source_p, const char *module)
515 {
516 char *m_bn = rb_basename(module);
517 int origin;
518
519 if(findmodule_byname(m_bn) != -1)
520 {
521 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
522 rb_free(m_bn);
523 return;
524 }
525
526 origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION;
527 load_one_module(module, origin, false);
528
529 rb_free(m_bn);
530 }
531
532 static void
533 do_modunload(struct Client *source_p, const char *module)
534 {
535 int modindex;
536 char *m_bn = rb_basename(module);
537
538 if((modindex = findmodule_byname(m_bn)) == -1)
539 {
540 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
541 rb_free(m_bn);
542 return;
543 }
544
545 if(modlist[modindex]->core)
546 {
547 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
548 rb_free(m_bn);
549 return;
550 }
551
552 if(unload_one_module(m_bn, true) == false)
553 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
554
555 rb_free(m_bn);
556 }
557
558 static void
559 do_modreload(struct Client *source_p, const char *module)
560 {
561 int modindex;
562 int check_core;
563 char *m_bn = rb_basename(module);
564
565 if((modindex = findmodule_byname(m_bn)) == -1)
566 {
567 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
568 rb_free(m_bn);
569 return;
570 }
571
572 check_core = modlist[modindex]->core;
573
574 if(unload_one_module(m_bn, true) == false)
575 {
576 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
577 rb_free(m_bn);
578 return;
579 }
580
581 if((load_one_module(m_bn, modlist[modindex]->origin, check_core) == false) && check_core)
582 {
583 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
584 "Error reloading core module: %s: terminating ircd", m_bn);
585 ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
586 exit(0);
587 }
588
589 rb_free(m_bn);
590 }
591
592 static void
593 do_modrestart(struct Client *source_p)
594 {
595 int modnum;
596
597 sendto_one_notice(source_p, ":Reloading all modules");
598
599 modnum = num_mods;
600 while (num_mods)
601 unload_one_module(modlist[0]->name, false);
602
603 load_all_modules(false);
604 load_core_modules(false);
605 rehash(false);
606
607 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
608 "Module Restart: %d modules unloaded, %d modules loaded",
609 modnum, num_mods);
610 ilog(L_MAIN, "Module Restart: %d modules unloaded, %d modules loaded", modnum, num_mods);
611 }
612
613 static void
614 do_modlist(struct Client *source_p, const char *pattern)
615 {
616 int i;
617
618 for (i = 0; i < num_mods; i++)
619 {
620 const char *origin;
621 switch (modlist[i]->origin)
622 {
623 case MAPI_ORIGIN_EXTENSION:
624 origin = "extension";
625 break;
626 case MAPI_ORIGIN_CORE:
627 origin = "builtin";
628 break;
629 default:
630 origin = "unknown";
631 break;
632 }
633
634 if(pattern)
635 {
636 if(match(pattern, modlist[i]->name))
637 {
638 sendto_one(source_p, form_str(RPL_MODLIST),
639 me.name, source_p->name,
640 modlist[i]->name,
641 (unsigned long)(uintptr_t)modlist[i]->address, origin,
642 modlist[i]->core ? " (core)" : "", modlist[i]->version, modlist[i]->description);
643 }
644 }
645 else
646 {
647 sendto_one(source_p, form_str(RPL_MODLIST),
648 me.name, source_p->name, modlist[i]->name,
649 (unsigned long)(uintptr_t)modlist[i]->address, origin,
650 modlist[i]->core ? " (core)" : "", modlist[i]->version, modlist[i]->description);
651 }
652 }
653
654 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
655 }
656
657 static void increase_modlist(void);
658
659 #define MODS_INCREMENT 10
660
661 static char unknown_ver[] = "<unknown>";
662 static char unknown_description[] = "<none>";
663
664 /* unload_one_module()
665 *
666 * inputs - name of module to unload
667 * - true to say modules unloaded, false to not
668 * output - true if successful, false if error
669 * side effects - module is unloaded
670 */
671 bool
672 unload_one_module(const char *name, bool warn)
673 {
674 int modindex;
675
676 if((modindex = findmodule_byname(name)) == -1)
677 return false;
678
679 /*
680 ** XXX - The type system in C does not allow direct conversion between
681 ** data and function pointers, but as it happens, most C compilers will
682 ** safely do this, however it is a theoretical overlow to cast as we
683 ** must do here. I have library functions to take care of this, but
684 ** despite being more "correct" for the C language, this is more
685 ** practical. Removing the abuse of the ability to cast ANY pointer
686 ** to and from an integer value here will break some compilers.
687 ** -jmallett
688 */
689 /* Left the comment in but the code isn't here any more -larne */
690 switch (modlist[modindex]->mapi_version)
691 {
692 case 1:
693 {
694 struct mapi_mheader_av1 *mheader = modlist[modindex]->mapi_header;
695 if(mheader->mapi_command_list)
696 {
697 struct Message **m;
698 for (m = mheader->mapi_command_list; *m; ++m)
699 mod_del_cmd(*m);
700 }
701
702 /* hook events are never removed, we simply lose the
703 * ability to call them --fl
704 */
705 if(mheader->mapi_hfn_list)
706 {
707 mapi_hfn_list_av1 *m;
708 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
709 remove_hook(m->hapi_name, m->fn);
710 }
711
712 if(mheader->mapi_unregister)
713 mheader->mapi_unregister();
714 break;
715 }
716 case 2:
717 {
718 struct mapi_mheader_av2 *mheader = modlist[modindex]->mapi_header;
719
720 /* XXX duplicate code :( */
721 if(mheader->mapi_command_list)
722 {
723 struct Message **m;
724 for (m = mheader->mapi_command_list; *m; ++m)
725 mod_del_cmd(*m);
726 }
727
728 /* hook events are never removed, we simply lose the
729 * ability to call them --fl
730 */
731 if(mheader->mapi_hfn_list)
732 {
733 mapi_hfn_list_av1 *m;
734 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
735 remove_hook(m->hapi_name, m->fn);
736 }
737
738 if(mheader->mapi_unregister)
739 mheader->mapi_unregister();
740
741 if(mheader->mapi_cap_list)
742 {
743 mapi_cap_list_av2 *m;
744 for (m = mheader->mapi_cap_list; m->cap_name; ++m)
745 {
746 struct CapabilityIndex *idx;
747
748 switch (m->cap_index)
749 {
750 case MAPI_CAP_CLIENT:
751 idx = cli_capindex;
752 break;
753 case MAPI_CAP_SERVER:
754 idx = serv_capindex;
755 break;
756 default:
757 sendto_realops_snomask(SNO_GENERAL, L_ALL,
758 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
759 m->cap_index, m->cap_name, modlist[modindex]->name);
760 ilog(L_MAIN,
761 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
762 m->cap_index, m->cap_name, modlist[modindex]->name);
763 continue;
764 }
765
766 if (m->cap_id != NULL)
767 {
768 capability_orphan(idx, m->cap_name);
769 sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * DEL :%s", me.name, m->cap_name);
770 }
771 }
772 }
773 }
774 default:
775 sendto_realops_snomask(SNO_GENERAL, L_ALL,
776 "Unknown/unsupported MAPI version %d when unloading %s!",
777 modlist[modindex]->mapi_version, modlist[modindex]->name);
778 ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
779 modlist[modindex]->mapi_version, modlist[modindex]->name);
780 break;
781 }
782
783 lt_dlclose(modlist[modindex]->address);
784
785 rb_free(modlist[modindex]->name);
786 rb_free(modlist[modindex]);
787 memmove(&modlist[modindex], &modlist[modindex + 1],
788 sizeof(struct module *) * ((num_mods - 1) - modindex));
789
790 if(num_mods != 0)
791 num_mods--;
792
793 if(warn)
794 {
795 ilog(L_MAIN, "Module %s unloaded", name);
796 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
797 }
798
799 return true;
800 }
801
802 /*
803 * load_a_module()
804 *
805 * inputs - path name of module, bool to notice, int of origin, bool if core
806 * output - false if error true if success
807 * side effects - loads a module if successful
808 */
809 bool
810 load_a_module(const char *path, bool warn, int origin, bool core)
811 {
812 lt_dlhandle tmpptr;
813 char *mod_basename;
814 const char *ver, *description = NULL;
815
816 int *mapi_version;
817
818 mod_basename = rb_basename(path);
819
820 tmpptr = lt_dlopenext(path);
821
822 if(tmpptr == NULL)
823 {
824 const char *err = lt_dlerror();
825
826 sendto_realops_snomask(SNO_GENERAL, L_ALL,
827 "Error loading module %s: %s", mod_basename, err);
828 ilog(L_MAIN, "Error loading module %s: %s", mod_basename, err);
829 rb_free(mod_basename);
830 return false;
831 }
832
833 /*
834 * _mheader is actually a struct mapi_mheader_*, but mapi_version
835 * is always the first member of this structure, so we treate it
836 * as a single int in order to determine the API version.
837 * -larne.
838 */
839 mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "_mheader");
840 if((mapi_version == NULL
841 && (mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "__mheader")) == NULL)
842 || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
843 {
844 sendto_realops_snomask(SNO_GENERAL, L_ALL,
845 "Data format error: module %s has no MAPI header.",
846 mod_basename);
847 ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_basename);
848 (void) lt_dlclose(tmpptr);
849 rb_free(mod_basename);
850 return false;
851 }
852
853 switch (MAPI_VERSION(*mapi_version))
854 {
855 case 1:
856 {
857 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *)(void *)mapi_version; /* see above */
858 if(mheader->mapi_register && (mheader->mapi_register() == -1))
859 {
860 ilog(L_MAIN, "Module %s indicated failure during load.",
861 mod_basename);
862 sendto_realops_snomask(SNO_GENERAL, L_ALL,
863 "Module %s indicated failure during load.",
864 mod_basename);
865 lt_dlclose(tmpptr);
866 rb_free(mod_basename);
867 return false;
868 }
869 if(mheader->mapi_command_list)
870 {
871 struct Message **m;
872 for (m = mheader->mapi_command_list; *m; ++m)
873 mod_add_cmd(*m);
874 }
875
876 if(mheader->mapi_hook_list)
877 {
878 mapi_hlist_av1 *m;
879 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
880 *m->hapi_id = register_hook(m->hapi_name);
881 }
882
883 if(mheader->mapi_hfn_list)
884 {
885 mapi_hfn_list_av1 *m;
886 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
887 add_hook(m->hapi_name, m->fn);
888 }
889
890 ver = mheader->mapi_module_version;
891 break;
892 }
893 case 2:
894 {
895 struct mapi_mheader_av2 *mheader = (struct mapi_mheader_av2 *)(void *)mapi_version; /* see above */
896
897 /* XXX duplicated code :( */
898 if(mheader->mapi_register && (mheader->mapi_register() == -1))
899 {
900 ilog(L_MAIN, "Module %s indicated failure during load.",
901 mod_basename);
902 sendto_realops_snomask(SNO_GENERAL, L_ALL,
903 "Module %s indicated failure during load.",
904 mod_basename);
905 lt_dlclose(tmpptr);
906 rb_free(mod_basename);
907 return false;
908 }
909
910 /* Basic date code checks
911 *
912 * Don't make them fatal, but do complain about differences within a certain time frame.
913 * Later on if there are major API changes we can add fatal checks.
914 * -- Elizafox
915 */
916 if(mheader->mapi_datecode != datecode && mheader->mapi_datecode > 0)
917 {
918 long int delta = datecode - mheader->mapi_datecode;
919 if (delta > MOD_WARN_DELTA)
920 {
921 delta /= 86400;
922 iwarn("Module %s build date is out of sync with ircd build date by %ld days, expect problems",
923 mod_basename, delta);
924 sendto_realops_snomask(SNO_GENERAL, L_ALL,
925 "Module %s build date is out of sync with ircd build date by %ld days, expect problems",
926 mod_basename, delta);
927 }
928 }
929
930 if(mheader->mapi_command_list)
931 {
932 struct Message **m;
933 for (m = mheader->mapi_command_list; *m; ++m)
934 mod_add_cmd(*m);
935 }
936
937 if(mheader->mapi_hook_list)
938 {
939 mapi_hlist_av1 *m;
940 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
941 *m->hapi_id = register_hook(m->hapi_name);
942 }
943
944 if(mheader->mapi_hfn_list)
945 {
946 mapi_hfn_list_av1 *m;
947 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
948 add_hook(m->hapi_name, m->fn);
949 }
950
951 /* New in MAPI v2 - version replacement */
952 ver = mheader->mapi_module_version ? mheader->mapi_module_version : ircd_version;
953 description = mheader->mapi_module_description;
954
955 if(mheader->mapi_cap_list)
956 {
957 mapi_cap_list_av2 *m;
958 for (m = mheader->mapi_cap_list; m->cap_name; ++m)
959 {
960 struct CapabilityIndex *idx;
961 int result;
962
963 switch (m->cap_index)
964 {
965 case MAPI_CAP_CLIENT:
966 idx = cli_capindex;
967 break;
968 case MAPI_CAP_SERVER:
969 idx = serv_capindex;
970 break;
971 default:
972 sendto_realops_snomask(SNO_GENERAL, L_ALL,
973 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
974 m->cap_index, m->cap_name, mod_basename);
975 ilog(L_MAIN,
976 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
977 m->cap_index, m->cap_name, mod_basename);
978 continue;
979 }
980
981 result = capability_put(idx, m->cap_name, m->cap_ownerdata);
982 if (m->cap_id != NULL)
983 {
984 *(m->cap_id) = result;
985 sendto_local_clients_with_capability(CLICAP_CAP_NOTIFY, ":%s CAP * ADD :%s", me.name, m->cap_name);
986 }
987 }
988 }
989 }
990
991 break;
992 default:
993 ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
994 mod_basename, MAPI_VERSION(*mapi_version));
995 sendto_realops_snomask(SNO_GENERAL, L_ALL,
996 "Module %s has unknown/unsupported MAPI version %d.",
997 mod_basename, *mapi_version);
998 lt_dlclose(tmpptr);
999 rb_free(mod_basename);
1000 return false;
1001 }
1002
1003 if(ver == NULL)
1004 ver = unknown_ver;
1005
1006 if(description == NULL)
1007 description = unknown_description;
1008
1009 increase_modlist();
1010
1011 modlist[num_mods] = rb_malloc(sizeof(struct module));
1012 modlist[num_mods]->address = tmpptr;
1013 modlist[num_mods]->version = ver;
1014 modlist[num_mods]->description = description;
1015 modlist[num_mods]->core = core;
1016 modlist[num_mods]->name = rb_strdup(mod_basename);
1017 modlist[num_mods]->mapi_header = mapi_version;
1018 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
1019 modlist[num_mods]->origin = origin;
1020 num_mods++;
1021
1022 if(warn)
1023 {
1024 const char *o;
1025
1026 switch (origin)
1027 {
1028 case MAPI_ORIGIN_EXTENSION:
1029 o = "extension";
1030 break;
1031 case MAPI_ORIGIN_CORE:
1032 o = "core";
1033 break;
1034 default:
1035 o = "unknown";
1036 break;
1037 }
1038
1039 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1040 "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
1041 mod_basename, ver, MAPI_VERSION(*mapi_version), o, description,
1042 (void *) tmpptr);
1043 ilog(L_MAIN, "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
1044 mod_basename, ver, MAPI_VERSION(*mapi_version), o, description, (void *) tmpptr);
1045 }
1046 rb_free(mod_basename);
1047 return true;
1048 }
1049
1050 /*
1051 * increase_modlist
1052 *
1053 * inputs - NONE
1054 * output - NONE
1055 * side effects - expand the size of modlist if necessary
1056 */
1057 static void
1058 increase_modlist(void)
1059 {
1060 struct module **new_modlist = NULL;
1061
1062 if((num_mods + 1) < max_mods)
1063 return;
1064
1065 new_modlist = (struct module **) rb_malloc(sizeof(struct module *) *
1066 (max_mods + MODS_INCREMENT));
1067 memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module *) * num_mods);
1068
1069 rb_free(modlist);
1070 modlist = new_modlist;
1071 max_mods += MODS_INCREMENT;
1072 }