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