]> jfr.im git - solanum.git/blame - ircd/modules.c
authd/providers/opm: configure port listeners correctly
[solanum.git] / ircd / modules.c
CommitLineData
212380e3
AC
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
212380e3
AC
23 */
24
25#include "stdinc.h"
212380e3 26#include "modules.h"
4016731b 27#include "logger.h"
212380e3
AC
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"
4562c604 36#include "match.h"
15feac53 37#include "s_serv.h"
8e9c6a75 38#include "capability.h"
212380e3 39
f272e7ab
AC
40#include <ltdl.h>
41
9abdcf1c
EM
42#ifndef LT_MODULE_EXT
43# error "Charybdis requires loadable module support."
44#endif
45
212380e3
AC
46struct module **modlist = NULL;
47
48static const char *core_module_table[] = {
431a1a27 49 "m_ban",
212380e3
AC
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",
212380e3
AC
61 "m_squit",
62 NULL
63};
64
81204be8
EM
65#define MOD_WARN_DELTA (90 * 86400) /* time in seconds, 86400 seconds in a day */
66
212380e3
AC
67#define MODS_INCREMENT 10
68int num_mods = 0;
69int max_mods = MODS_INCREMENT;
70
330fc5c1 71static rb_dlink_list mod_paths;
212380e3 72
3c7d6fcc
EM
73static void mo_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
74static void mo_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
75static void mo_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
76static void mo_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
77static void mo_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
78
79static void me_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
80static void me_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
81static void me_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
82static void me_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
83static void me_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
84
85static void do_modload(struct Client *, const char *);
86static void do_modunload(struct Client *, const char *);
87static void do_modreload(struct Client *, const char *);
88static void do_modlist(struct Client *, const char *);
89static void do_modrestart(struct Client *);
15feac53 90
212380e3 91struct Message modload_msgtab = {
7baa37a9 92 "MODLOAD", 0, 0, 0, 0,
15feac53 93 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
212380e3
AC
94};
95
96struct Message modunload_msgtab = {
7baa37a9 97 "MODUNLOAD", 0, 0, 0, 0,
15feac53 98 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modunload, 2}, {mo_modunload, 2}}
212380e3
AC
99};
100
101struct Message modreload_msgtab = {
7baa37a9 102 "MODRELOAD", 0, 0, 0, 0,
15feac53 103 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modreload, 2}, {mo_modreload, 2}}
212380e3
AC
104};
105
106struct Message modlist_msgtab = {
7baa37a9 107 "MODLIST", 0, 0, 0, 0,
15feac53 108 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modlist, 0}, {mo_modlist, 0}}
212380e3
AC
109};
110
111struct Message modrestart_msgtab = {
7baa37a9 112 "MODRESTART", 0, 0, 0, 0,
15feac53 113 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0}}
212380e3
AC
114};
115
212380e3
AC
116void
117modules_init(void)
118{
f272e7ab
AC
119 if(lt_dlinit())
120 {
121 ilog(L_MAIN, "lt_dlinit failed");
122 exit(0);
123 }
124
212380e3
AC
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 */
4d8cfacd
AC
132 mod_add_path(ircd_paths[IRCD_PATH_MODULES]);
133 mod_add_path(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]);
212380e3
AC
134}
135
136/* mod_find_path()
137 *
138 * input - path
139 * output - none
140 * side effects - returns a module path from path
141 */
26c6ac3d 142static char *
212380e3
AC
143mod_find_path(const char *path)
144{
330fc5c1 145 rb_dlink_node *ptr;
26c6ac3d 146 char *mpath;
212380e3 147
5cefa1d6 148 RB_DLINK_FOREACH(ptr, mod_paths.head)
212380e3
AC
149 {
150 mpath = ptr->data;
151
26c6ac3d 152 if(!strcmp(path, mpath))
212380e3
AC
153 return mpath;
154 }
155
156 return NULL;
157}
158
159/* mod_add_path
160 *
161 * input - path
55abcbb2 162 * ouput -
212380e3
AC
163 * side effects - adds path to list
164 */
165void
166mod_add_path(const char *path)
167{
26c6ac3d 168 char *pathst;
212380e3
AC
169
170 if(mod_find_path(path))
171 return;
172
26c6ac3d 173 pathst = rb_strdup(path);
330fc5c1 174 rb_dlinkAddAlloc(pathst, &mod_paths);
212380e3
AC
175}
176
177/* mod_clear_paths()
178 *
179 * input -
180 * output -
181 * side effects - clear the lists of paths
182 */
183void
184mod_clear_paths(void)
185{
637c4932 186 rb_dlink_node *ptr, *next_ptr;
212380e3 187
637c4932 188 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
212380e3 189 {
637c4932 190 rb_free(ptr->data);
30106156 191 rb_free_rb_dlink_node(ptr);
212380e3
AC
192 }
193
194 mod_paths.head = mod_paths.tail = NULL;
195 mod_paths.length = 0;
196}
197
212380e3
AC
198/* findmodule_byname
199 *
200 * input -
201 * output -
202 * side effects -
203 */
204
205int
206findmodule_byname(const char *name)
207{
208 int i;
c9108ea0
AC
209 char name_ext[PATH_MAX + 1];
210
dd92c99b
AC
211 rb_strlcpy(name_ext, name, sizeof name_ext);
212 rb_strlcat(name_ext, LT_MODULE_EXT, sizeof name_ext);
212380e3
AC
213
214 for (i = 0; i < num_mods; i++)
215 {
216 if(!irccmp(modlist[i]->name, name))
217 return i;
c9108ea0
AC
218
219 if(!irccmp(modlist[i]->name, name_ext))
220 return i;
212380e3 221 }
c9108ea0 222
212380e3
AC
223 return -1;
224}
225
226/* load_all_modules()
227 *
228 * input -
229 * output -
230 * side effects -
231 */
232void
233load_all_modules(int warn)
234{
235 DIR *system_module_dir = NULL;
236 struct dirent *ldirent = NULL;
237 char module_fq_name[PATH_MAX + 1];
1db8a313
EM
238 size_t module_ext_len = strlen(LT_MODULE_EXT);
239
212380e3
AC
240 modules_init();
241
1e170010 242 modlist = (struct module **) rb_malloc(sizeof(struct module *) * (MODS_INCREMENT));
212380e3
AC
243
244 max_mods = MODS_INCREMENT;
245
4d8cfacd 246 system_module_dir = opendir(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]);
212380e3
AC
247
248 if(system_module_dir == NULL)
249 {
4d8cfacd 250 ilog(L_MAIN, "Could not load modules from %s: %s", ircd_paths[IRCD_PATH_AUTOLOAD_MODULES], strerror(errno));
212380e3
AC
251 return;
252 }
253
254 while ((ldirent = readdir(system_module_dir)) != NULL)
255 {
9abdcf1c
EM
256 size_t len;
257
5203cba5 258 len = strlen(ldirent->d_name);
9abdcf1c 259 if(len > module_ext_len && !strcasecmp(ldirent->d_name + (len - module_ext_len), LT_MODULE_EXT))
5203cba5 260 {
4d8cfacd 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);
216d70e9 262 (void) load_a_module(module_fq_name, warn, MAPI_ORIGIN_CORE, 0);
5203cba5 263 }
212380e3
AC
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 */
275void
276load_core_modules(int warn)
277{
d74fa5b5 278 char module_name[PATH_MAX];
212380e3
AC
279 int i;
280
281
282 for (i = 0; core_module_table[i]; i++)
283 {
4d8cfacd 284 snprintf(module_name, sizeof(module_name), "%s%c%s%s", ircd_paths[IRCD_PATH_MODULES], RB_PATH_SEPARATOR,
6cb643f4 285 core_module_table[i], LT_MODULE_EXT);
212380e3 286
216d70e9 287 if(load_a_module(module_name, warn, MAPI_ORIGIN_CORE, 1) == -1)
212380e3
AC
288 {
289 ilog(L_MAIN,
9abdcf1c
EM
290 "Error loading core module %s: terminating ircd",
291 core_module_table[i]);
212380e3
AC
292 exit(0);
293 }
294 }
295}
296
297/* load_one_module()
298 *
299 * input -
300 * output -
301 * side effects -
302 */
303int
216d70e9 304load_one_module(const char *path, int origin, int coremodule)
212380e3 305{
d74fa5b5 306 char modpath[PATH_MAX];
330fc5c1 307 rb_dlink_node *pathst;
26c6ac3d 308 const char *mpath;
212380e3
AC
309 struct stat statbuf;
310
503727d1 311 if (server_state_foreground)
55abcbb2 312 inotice("loading module %s ...", path);
212380e3 313
216d70e9
EM
314 if(coremodule != 0)
315 {
316 coremodule = 1;
317 origin = MAPI_ORIGIN_CORE;
318 }
319
5cefa1d6 320 RB_DLINK_FOREACH(pathst, mod_paths.head)
212380e3
AC
321 {
322 mpath = pathst->data;
323
6cb643f4 324 snprintf(modpath, sizeof(modpath), "%s/%s%s", mpath, path, LT_MODULE_EXT);
212380e3
AC
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 */
216d70e9 332 return load_a_module(modpath, 1, origin, coremodule);
212380e3
AC
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 .. */
3c7d6fcc 345static void
4a84a763 346mo_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 347{
212380e3
AC
348 if(!IsOperAdmin(source_p))
349 {
350 sendto_one(source_p, form_str(ERR_NOPRIVS),
351 me.name, source_p->name, "admin");
3c7d6fcc 352 return;
212380e3
AC
353 }
354
15feac53
AC
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)
3c7d6fcc 360 return;
15feac53
AC
361 }
362
3c7d6fcc 363 do_modload(source_p, parv[1]);
15feac53
AC
364}
365
3c7d6fcc 366static void
4a84a763 367me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
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.");
3c7d6fcc 373 return;
15feac53
AC
374 }
375
3c7d6fcc 376 do_modload(source_p, parv[1]);
15feac53
AC
377}
378
3c7d6fcc
EM
379
380/* unload a module .. */
381static void
382mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53 383{
3c7d6fcc
EM
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 }
212380e3 390
3c7d6fcc 391 if(parc > 2)
212380e3 392 {
3c7d6fcc
EM
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;
212380e3
AC
397 }
398
3c7d6fcc
EM
399 do_modunload(source_p, parv[1]);
400}
212380e3 401
3c7d6fcc
EM
402static void
403me_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 }
212380e3 411
3c7d6fcc 412 do_modunload(source_p, parv[1]);
212380e3
AC
413}
414
3c7d6fcc
EM
415/* unload and load in one! */
416static void
417mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 418{
212380e3
AC
419 if(!IsOperAdmin(source_p))
420 {
421 sendto_one(source_p, form_str(ERR_NOPRIVS),
422 me.name, source_p->name, "admin");
3c7d6fcc 423 return;
212380e3
AC
424 }
425
15feac53
AC
426 if(parc > 2)
427 {
428 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
3c7d6fcc 429 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
15feac53 430 if (match(parv[2], me.name) == 0)
3c7d6fcc 431 return;
15feac53
AC
432 }
433
3c7d6fcc 434 do_modreload(source_p, parv[1]);
15feac53
AC
435}
436
3c7d6fcc
EM
437static void
438me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
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.");
3c7d6fcc 444 return;
15feac53
AC
445 }
446
3c7d6fcc 447 do_modreload(source_p, parv[1]);
15feac53
AC
448}
449
3c7d6fcc
EM
450/* list modules .. */
451static void
452mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53 453{
3c7d6fcc 454 if(!IsOperAdmin(source_p))
212380e3 455 {
3c7d6fcc
EM
456 sendto_one(source_p, form_str(ERR_NOPRIVS),
457 me.name, source_p->name, "admin");
458 return;
212380e3
AC
459 }
460
3c7d6fcc 461 if(parc > 2)
212380e3 462 {
3c7d6fcc
EM
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;
212380e3
AC
467 }
468
3c7d6fcc
EM
469 do_modlist(source_p, parc > 1 ? parv[1] : 0);
470}
471
472static void
473me_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))
212380e3 476 {
3c7d6fcc
EM
477 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
478 "to load modules on this server.");
479 return;
212380e3 480 }
5366977b 481
3c7d6fcc 482 do_modlist(source_p, parv[1]);
212380e3
AC
483}
484
3c7d6fcc
EM
485/* unload and reload all modules */
486static void
487mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 488{
212380e3
AC
489 if(!IsOperAdmin(source_p))
490 {
491 sendto_one(source_p, form_str(ERR_NOPRIVS),
492 me.name, source_p->name, "admin");
3c7d6fcc 493 return;
212380e3
AC
494 }
495
3c7d6fcc 496 if(parc > 1)
15feac53 497 {
3c7d6fcc
EM
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;
15feac53
AC
502 }
503
3c7d6fcc 504 do_modrestart(source_p);
15feac53
AC
505}
506
3c7d6fcc
EM
507static void
508me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
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.");
3c7d6fcc 514 return;
15feac53
AC
515 }
516
3c7d6fcc 517 do_modrestart(source_p);
15feac53
AC
518}
519
3c7d6fcc
EM
520static void
521do_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
539static void
540do_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
567static void
15feac53
AC
568do_modreload(struct Client *source_p, const char *module)
569{
570 int modindex;
571 int check_core;
572 char *m_bn = rb_basename(module);
212380e3
AC
573
574 if((modindex = findmodule_byname(m_bn)) == -1)
575 {
5366977b 576 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
637c4932 577 rb_free(m_bn);
3c7d6fcc 578 return;
212380e3
AC
579 }
580
581 check_core = modlist[modindex]->core;
582
583 if(unload_one_module(m_bn, 1) == -1)
584 {
5366977b 585 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
637c4932 586 rb_free(m_bn);
3c7d6fcc 587 return;
212380e3
AC
588 }
589
216d70e9 590 if((load_one_module(m_bn, modlist[modindex]->origin, check_core) == -1) && check_core)
212380e3 591 {
15feac53 592 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
7d778d51
AC
593 "Error reloading core module: %s: terminating ircd", m_bn);
594 ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
212380e3
AC
595 exit(0);
596 }
597
637c4932 598 rb_free(m_bn);
212380e3
AC
599}
600
3c7d6fcc
EM
601static void
602do_modrestart(struct Client *source_p)
212380e3 603{
3c7d6fcc 604 int modnum;
212380e3 605
3c7d6fcc 606 sendto_one_notice(source_p, ":Reloading all modules");
15feac53 607
3c7d6fcc
EM
608 modnum = num_mods;
609 while (num_mods)
610 unload_one_module(modlist[0]->name, 0);
15feac53 611
3c7d6fcc
EM
612 load_all_modules(0);
613 load_core_modules(0);
614 rehash(0);
15feac53 615
3c7d6fcc
EM
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);
15feac53
AC
620}
621
3c7d6fcc 622static void
15feac53
AC
623do_modlist(struct Client *source_p, const char *pattern)
624{
625 int i;
626
212380e3
AC
627 for (i = 0; i < num_mods; i++)
628 {
978b7232
EM
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
15feac53 643 if(pattern)
212380e3 644 {
15feac53 645 if(match(pattern, modlist[i]->name))
212380e3
AC
646 {
647 sendto_one(source_p, form_str(RPL_MODLIST),
648 me.name, source_p->name,
649 modlist[i]->name,
978b7232
EM
650 (unsigned long)(uintptr_t)modlist[i]->address, origin,
651 modlist[i]->core ? " (core)" : "", modlist[i]->version, modlist[i]->description);
212380e3
AC
652 }
653 }
654 else
655 {
656 sendto_one(source_p, form_str(RPL_MODLIST),
657 me.name, source_p->name, modlist[i]->name,
978b7232
EM
658 (unsigned long)(uintptr_t)modlist[i]->address, origin,
659 modlist[i]->core ? " (core)" : "", modlist[i]->version, modlist[i]->description);
212380e3
AC
660 }
661 }
662
663 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
15feac53
AC
664}
665
212380e3
AC
666static void increase_modlist(void);
667
668#define MODS_INCREMENT 10
669
670static char unknown_ver[] = "<unknown>";
8e9c6a75 671static char unknown_description[] = "<none>";
212380e3 672
212380e3
AC
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 */
680int
681unload_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
55abcbb2
KB
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
212380e3
AC
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 }
8e9c6a75
EM
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
978b7232 757 switch (m->cap_index)
8e9c6a75
EM
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 }
212380e3
AC
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
f272e7ab 788 lt_dlclose(modlist[modindex]->address);
212380e3 789
637c4932 790 rb_free(modlist[modindex]->name);
55d5f797 791 rb_free(modlist[modindex]);
f54e1a8f 792 memmove(&modlist[modindex], &modlist[modindex + 1],
1e170010 793 sizeof(struct module *) * ((num_mods - 1) - modindex));
212380e3
AC
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
212380e3
AC
807/*
808 * load_a_module()
809 *
216d70e9 810 * inputs - path name of module, int to notice, int of origin, int of core
212380e3
AC
811 * output - -1 if error 0 if success
812 * side effects - loads a module if successful
813 */
814int
216d70e9 815load_a_module(const char *path, int warn, int origin, int core)
212380e3 816{
f272e7ab 817 lt_dlhandle tmpptr;
212380e3 818 char *mod_basename;
8e9c6a75 819 const char *ver, *description = NULL;
212380e3
AC
820
821 int *mapi_version;
822
b7a689d1 823 mod_basename = rb_basename(path);
212380e3 824
9abdcf1c 825 tmpptr = lt_dlopenext(path);
212380e3
AC
826
827 if(tmpptr == NULL)
828 {
f272e7ab 829 const char *err = lt_dlerror();
212380e3
AC
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);
637c4932 834 rb_free(mod_basename);
212380e3
AC
835 return -1;
836 }
837
212380e3
AC
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 */
f272e7ab 844 mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "_mheader");
212380e3 845 if((mapi_version == NULL
f272e7ab 846 && (mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "__mheader")) == NULL)
212380e3
AC
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);
f272e7ab 853 (void) lt_dlclose(tmpptr);
637c4932 854 rb_free(mod_basename);
212380e3
AC
855 return -1;
856 }
857
858 switch (MAPI_VERSION(*mapi_version))
859 {
860 case 1:
861 {
29c92cf9 862 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *)(void *)mapi_version; /* see above */
212380e3
AC
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);
f272e7ab 870 lt_dlclose(tmpptr);
637c4932 871 rb_free(mod_basename);
212380e3
AC
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 }
8e9c6a75
EM
898 case 2:
899 {
900 struct mapi_mheader_av2 *mheader = (struct mapi_mheader_av2 *)(void *)mapi_version; /* see above */
212380e3 901
8e9c6a75
EM
902 /* XXX duplicated code :( */
903 if(mheader->mapi_register && (mheader->mapi_register() == -1))
904 {
905 ilog(L_MAIN, "Module %s indicated failure during load.",
81204be8 906 mod_basename);
8e9c6a75
EM
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 }
81204be8
EM
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 {
3089f59c 923 long int delta = datecode - mheader->mapi_datecode;
81204be8
EM
924 if (delta > MOD_WARN_DELTA)
925 {
926 delta /= 86400;
881acf00 927 iwarn("Module %s build date is out of sync with ircd build date by %ld days, expect problems",
81204be8
EM
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
8e9c6a75
EM
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
978b7232 968 switch (m->cap_index)
8e9c6a75
EM
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 }
0e5bf029
EM
992
993 break;
212380e3
AC
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);
f272e7ab 1000 lt_dlclose(tmpptr);
637c4932 1001 rb_free(mod_basename);
212380e3
AC
1002 return -1;
1003 }
1004
1005 if(ver == NULL)
1006 ver = unknown_ver;
1007
8e9c6a75
EM
1008 if(description == NULL)
1009 description = unknown_description;
1010
212380e3
AC
1011 increase_modlist();
1012
eddc2ab6 1013 modlist[num_mods] = rb_malloc(sizeof(struct module));
212380e3
AC
1014 modlist[num_mods]->address = tmpptr;
1015 modlist[num_mods]->version = ver;
0eb7d9c0 1016 modlist[num_mods]->description = description;
212380e3 1017 modlist[num_mods]->core = core;
47a03750 1018 modlist[num_mods]->name = rb_strdup(mod_basename);
212380e3
AC
1019 modlist[num_mods]->mapi_header = mapi_version;
1020 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
c63aeb44 1021 modlist[num_mods]->origin = origin;
212380e3
AC
1022 num_mods++;
1023
1024 if(warn == 1)
1025 {
c63aeb44
EM
1026 const char *o;
1027
978b7232 1028 switch (origin)
c63aeb44 1029 {
c63aeb44
EM
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
212380e3 1041 sendto_realops_snomask(SNO_GENERAL, L_ALL,
02831b6f 1042 "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
c63aeb44 1043 mod_basename, ver, MAPI_VERSION(*mapi_version), o, description,
02831b6f
AC
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);
212380e3 1047 }
637c4932 1048 rb_free(mod_basename);
212380e3
AC
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 */
1059static void
1060increase_modlist(void)
1061{
1062 struct module **new_modlist = NULL;
1063
1064 if((num_mods + 1) < max_mods)
1065 return;
1066
1e170010 1067 new_modlist = (struct module **) rb_malloc(sizeof(struct module *) *
212380e3 1068 (max_mods + MODS_INCREMENT));
1e170010 1069 memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module *) * num_mods);
212380e3 1070
637c4932 1071 rb_free(modlist);
212380e3
AC
1072 modlist = new_modlist;
1073 max_mods += MODS_INCREMENT;
1074}