1 /************************************************************************
2 * UnrealIRCd - Unreal Internet Relay Chat Daemon - src/modules.c
3 * (C) 2001 Carsten Munk (Techie/Stskeeps) <stskeeps@tspre.org>
4 *
5 * See file AUTHORS in IRC package for additional names of
6 * the programmers.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 1, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * $Id$
23 */
24
25 #include "struct.h"
26 #include "common.h"
27 #include "sys.h"
28 #include "numeric.h"
29 #include "msg.h"
30 #include "channel.h"
31 #include "version.h"
32 #include <time.h>
33 #include <sys/stat.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <limits.h>
38 #ifdef _WIN32
39 #include <io.h>
40 #define RTLD_NOW 0
41 const char *our_dlerror(void);
42 #elif defined(HPUX)
43 #include <dl.h>
44 #define RTLD_NOW BIND_IMMEDIATE
45 #else
46 #include <dlfcn.h>
47 #endif
48 #include <fcntl.h>
49 #ifndef _WIN32
50 #include <dirent.h>
51 #endif
52 #include "h.h"
53 #include "proto.h"
54 #ifndef RTLD_NOW
55 #define RTLD_NOW RTLD_LAZY
56 #endif
57 #define UNREALCORE
58 #include "modversion.h"
59
60 Hook *Hooks[MAXHOOKTYPES];
61 Hooktype Hooktypes[MAXCUSTOMHOOKS];
62 Callback *Callbacks[MAXCALLBACKS]; /* Callback objects for modules, used for rehashing etc (can be multiple) */
63 Callback *RCallbacks[MAXCALLBACKS]; /* 'Real' callback function, used for callback function calls */
64 Efunction *Efunctions[MAXEFUNCTIONS]; /* Efunction objects (used for rehashing) */
65 MODVAR Module *Modules = NULL;
66 MODVAR Versionflag *Versionflags = NULL;
67
68 int Module_Depend_Resolve(Module *p, char *path);
69 Module *Module_make(ModuleHeader *header,
70 #ifdef _WIN32
71 HMODULE mod
72 #else
73 void *mod
74 #endif
75 );
76
77 typedef struct {
78 char *name;
79 void **funcptr;
80 } EfunctionsList;
81
82 /* Efuncs */
83 int (*do_join)(aClient *cptr, aClient *sptr, int parc, char *parv[]);
84 void (*join_channel)(aChannel *chptr, aClient *cptr, aClient *sptr, int flags);
85 int (*can_join)(aClient *cptr, aClient *sptr, aChannel *chptr, char *key, char *link, char *parv[]);
86 void (*do_mode)(aChannel *chptr, aClient *cptr, aClient *sptr, int parc, char *parv[], time_t sendts, int samode);
87 void (*set_mode)(aChannel *chptr, aClient *cptr, int parc, char *parv[], u_int *pcount,
88 char pvar[MAXMODEPARAMS][MODEBUFLEN + 3], int bounce);
89 int (*m_umode)(aClient *cptr, aClient *sptr, int parc, char *parv[]);
90 int (*register_user)(aClient *cptr, aClient *sptr, char *nick, char *username, char *umode, char *virthost, char *ip);
91 int (*tkl_hash)(unsigned int c);
92 char (*tkl_typetochar)(int type);
93 aTKline *(*tkl_add_line)(int type, char *usermask, char *hostmask, char *reason, char *setby,
94 TS expire_at, TS set_at, TS spamf_tkl_duration, char *spamf_tkl_reason);
95 aTKline *(*tkl_del_line)(aTKline *tkl);
96 void (*tkl_check_local_remove_shun)(aTKline *tmp);
97 aTKline *(*tkl_expire)(aTKline * tmp);
98 EVENT((*tkl_check_expire));
99 int (*find_tkline_match)(aClient *cptr, int xx);
100 int (*find_shun)(aClient *cptr);
101 int(*find_spamfilter_user)(aClient *sptr, int flags);
102 aTKline *(*find_qline)(aClient *cptr, char *nick, int *ishold);
103 int (*find_tkline_match_zap)(aClient *cptr);
104 void (*tkl_stats)(aClient *cptr, int type, char *para);
105 void (*tkl_synch)(aClient *sptr);
106 int (*m_tkl)(aClient *cptr, aClient *sptr, int parc, char *parv[]);
107 int (*place_host_ban)(aClient *sptr, int action, char *reason, long duration);
108 int (*dospamfilter)(aClient *sptr, char *str_in, int type, char *target, int flags, aTKline **rettk);
109 int (*dospamfilter_viruschan)(aClient *sptr, aTKline *tk, int type);
110 int (*find_tkline_match_zap_ex)(aClient *cptr, aTKline **rettk);
111 void (*send_list)(aClient *cptr, int numsend);
112 char *(*stripbadwords_channel)(char *str, int *blocked);
113 char *(*stripbadwords_message)(char *str, int *blocked);
114 char *(*stripbadwords_quit)(char *str, int *blocked);
115 unsigned char *(*StripColors)(unsigned char *text);
116 const char *(*StripControlCodes)(unsigned char *text);
117 void (*spamfilter_build_user_string)(char *buf, char *nick, aClient *acptr);
118 int (*is_silenced)(aClient *sptr, aClient *acptr);
119 void (*send_protoctl_servers)(aClient *sptr, int response);
120 int (*verify_link)(aClient *cptr, aClient *sptr, char *servername, ConfigItem_link **link_out);
121 void (*send_server_message)(aClient *sptr);
122
123 static const EfunctionsList efunction_table[MAXEFUNCTIONS] = {
124 /* 00 */ {NULL, NULL},
125 /* 01 */ {"do_join", (void *)&do_join},
126 /* 02 */ {"join_channel", (void *)&join_channel},
127 /* 03 */ {"can_join", (void *)&can_join},
128 /* 04 */ {"do_mode", (void *)&do_mode},
129 /* 05 */ {"set_mode", (void *)&set_mode},
130 /* 06 */ {"m_umode", (void *)&m_umode},
131 /* 07 */ {"register_user", (void *)®ister_user},
132 /* 08 */ {"tkl_hash", (void *)&tkl_hash},
133 /* 09 */ {"tkl_typetochar", (void *)&tkl_typetochar},
134 /* 10 */ {"tkl_add_line", (void *)&tkl_add_line},
135 /* 11 */ {"tkl_del_line", (void *)&tkl_del_line},
136 /* 12 */ {"tkl_check_local_remove_shun", (void *)&tkl_check_local_remove_shun},
137 /* 13 */ {"tkl_expire", (void *)&tkl_expire},
138 /* 14 */ {"tkl_check_expire", (void *)&tkl_check_expire},
139 /* 15 */ {"find_tkline_match", (void *)&find_tkline_match},
140 /* 16 */ {"find_shun", (void *)&find_shun},
141 /* 17 */ {"find_spamfilter_user", (void *)&find_spamfilter_user},
142 /* 18 */ {"find_qline", (void *)&find_qline},
143 /* 19 */ {"find_tkline_match_zap", (void *)&find_tkline_match_zap},
144 /* 20 */ {"tkl_stats", (void *)&tkl_stats},
145 /* 21 */ {"tkl_synch", (void *)&tkl_synch},
146 /* 22 */ {"m_tkl", (void *)&m_tkl},
147 /* 23 */ {"place_host_ban", (void *)&place_host_ban},
148 /* 24 */ {"dospamfilter", (void *)&dospamfilter},
149 /* 25 */ {"dospamfilter_viruschan", (void *)&dospamfilter_viruschan},
150 /* 26 */ {"find_tkline_match_zap_ex", (void *)&find_tkline_match_zap_ex},
151 /* 27 */ {"send_list", (void *)&send_list},
152 /* 28 */ {"stripbadwords_channel", (void *)&stripbadwords_channel},
153 /* 29 */ {"stripbadwords_message", (void *)&stripbadwords_message},
154 /* 30 */ {"stripbadwords_quit", (void *)&stripbadwords_quit},
155 /* 31 */ {"StripColors", (void *)&StripColors},
156 /* 32 */ {"StripControlCodes", (void *)&StripControlCodes},
157 /* 33 */ {"spamfilter_build_user_string", (void *)&spamfilter_build_user_string},
158 /* 34 */ {"is_silenced", (void *)&is_silenced},
159 /* 35 */ {"send_protoctl_servers", (void *)&send_protoctl_servers},
160 /* 36 */ {"verify_link", (void *)&verify_link},
161 /* 37 */ {"send_server_message", (void *)&send_server_message},
162 /* 38 */ {NULL, NULL}
163 };
164
165
166 #ifdef UNDERSCORE
obsd_dlsym(void * handle,char * symbol)167 void *obsd_dlsym(void *handle, char *symbol) {
168 char *obsdsymbol = (char*)MyMalloc(strlen(symbol) + 2);
169 void *symaddr = NULL;
170
171 if (obsdsymbol) {
172 sprintf(obsdsymbol, "_%s", symbol);
173 symaddr = dlsym(handle, obsdsymbol);
174 free(obsdsymbol);
175 }
176
177 return symaddr;
178 }
179 #endif
180
181
DeleteTempModules(void)182 void DeleteTempModules(void)
183 {
184 char tempbuf[PATH_MAX+1];
185 #ifndef _WIN32
186 DIR *fd = opendir("/var/run/ircd/tmp");
187 struct dirent *dir;
188
189 if (!fd) /* Ouch.. this is NOT good!! */
190 {
191 config_error("Unable to open '/var/run/ircd' directory: %s, please create one with the appropriate permissions",
192 strerror(errno));
193 if (!loop.ircd_booted)
194 exit(7);
195 return;
196 }
197
198 while ((dir = readdir(fd)))
199 {
200 if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
201 continue;
202 strcpy(tempbuf, "/var/run/ircd/tmp/");
203 strcat(tempbuf, dir->d_name);
204 remove(tempbuf);
205 }
206 closedir(fd);
207 #else
208 WIN32_FIND_DATA hData;
209 HANDLE hFile = FindFirstFile("/var/run/ircd/tmp/*", &hData);
210 if (hFile != INVALID_HANDLE_VALUE)
211 {
212 if (strcmp(hData.cFileName, ".") || strcmp(hData.cFileName, ".."))
213 {
214 strcpy(tempbuf, "/var/run/ircd/tmp/");
215 strcat(tempbuf, hData.cFileName);
216 remove(tempbuf);
217 }
218 }
219 while (FindNextFile(hFile, &hData))
220 {
221 if (!strcmp(hData.cFileName, ".") || !strcmp(hData.cFileName, ".."))
222 continue;
223 strcpy(tempbuf, "/var/run/ircd/tmp/");
224 strcat(tempbuf, hData.cFileName);
225 remove(tempbuf);
226 }
227 FindClose(hFile);
228 #endif
229 }
230
Module_Init(void)231 void Module_Init(void)
232 {
233 bzero(Hooks, sizeof(Hooks));
234 bzero(Hooktypes, sizeof(Hooktypes));
235 bzero(Callbacks, sizeof(Callback));
236 bzero(RCallbacks, sizeof(Callback));
237 bzero(Efunctions, sizeof(Efunction));
238 }
239
Module_Find(char * name)240 Module *Module_Find(char *name)
241 {
242 Module *p;
243
244 for (p = Modules; p; p = p->next)
245 {
246 if (!(p->options & MOD_OPT_PERM) &&
247 (!(p->flags & MODFLAG_TESTING) || (p->flags & MODFLAG_DELAYED)))
248 continue;
249 if (!strcmp(p->header->name, name))
250 {
251 return (p);
252 }
253 }
254 return NULL;
255
256 }
257
parse_modsys_version(char * version)258 int parse_modsys_version(char *version)
259 {
260 int betaversion, tag;
261 if (!strcmp(version, "3.2.3"))
262 return 0x32300;
263 if (sscanf(version, "3.2-b%d-%d", &betaversion, &tag))
264 {
265 switch (betaversion)
266 {
267 case 5:
268 return 0x320b5;
269 case 6:
270 return 0x320b6;
271 case 7:
272 return 0x320b7;
273 case 8:
274 return 0x320b8;
275 default:
276 return 0;
277 }
278 }
279 return 0;
280 }
281
make_compiler_string(char * buf,unsigned int ver)282 void make_compiler_string(char *buf, unsigned int ver)
283 {
284 unsigned int maj, min, plevel;
285
286 if (ver == 0)
287 {
288 strcpy(buf, "0");
289 return;
290 }
291
292 maj = ver >> 16;
293 min = (ver >> 8) & 0xff;
294 plevel = ver & 0xff;
295
296 if (plevel == 0)
297 sprintf(buf, "%d.%d", maj, min);
298 else
299 sprintf(buf, "%d.%d.%d", maj, min, plevel);
300 }
301
302 /*
303 * Returns an error if insucessful .. yes NULL is OK!
304 */
Module_Create(char * path_)305 char *Module_Create(char *path_)
306 {
307 #ifndef STATIC_LINKING
308 #ifdef _WIN32
309 HMODULE Mod;
310 #else /* _WIN32 */
311 void *Mod;
312 #endif /* _WIN32 */
313 int (*Mod_Test)();
314 int (*Mod_Init)();
315 int (*Mod_Load)();
316 int (*Mod_Unload)();
317 char *Mod_Version;
318 unsigned int *compiler_version;
319 static char errorbuf[1024];
320 char *path, *tmppath;
321 ModuleHeader *mod_header = NULL;
322 int ret = 0;
323 Module *mod = NULL, **Mod_Handle = NULL;
324 char *expectedmodversion = our_mod_version;
325 unsigned int expectedcompilerversion = our_compiler_version;
326 long modsys_ver = 0;
327 Debug((DEBUG_DEBUG, "Attempting to load module from %s",
328 path_));
329 path = path_;
330
331
332 tmppath = unreal_mktemp("/var/run/ircd/tmp", unreal_getfilename(path));
333 if (!tmppath)
334 return "Unable to create temporary file!";
335 #ifndef _WIN32
336 if(!strchr(path, '/'))
337 #else
338 if (!strchr(path, '\\') && !strchr(path, '/'))
339 #endif
340 {
341 path = MyMalloc(strlen(path) + 3);
342 strcpy(path, "./");
343 strcat(path, path_);
344 }
345
346 if (!file_exists(path))
347 {
348 snprintf(errorbuf, sizeof(errorbuf), "Cannot open module file: %s", strerror(errno));
349 return errorbuf;
350 }
351 /* For OpenBSD, do not do a hardlinkink attempt first because it checks inode
352 * numbers to see if a certain module is already loaded. -- Syzop
353 * EDIT (2009): Looks like Linux got smart too, from now on we always copy....
354 */
355 ret = unreal_copyfileex(path, tmppath, 0);
356 if (!ret)
357 {
358 snprintf(errorbuf, sizeof(errorbuf), "Failed to copy module file.");
359 return errorbuf;
360 }
361 if ((Mod = irc_dlopen(tmppath, RTLD_NOW)))
362 {
363 /* We have engaged the borg cube. Scan for lifesigns. */
364 irc_dlsym(Mod, "Mod_Version", Mod_Version);
365 if (Mod_Version && strcmp(Mod_Version, expectedmodversion))
366 {
367 snprintf(errorbuf, sizeof(errorbuf),
368 "Module was compiled for '%s', we were configured for '%s'. SOLUTION: Recompile the module(s).",
369 Mod_Version, expectedmodversion);
370 irc_dlclose(Mod);
371 remove(tmppath);
372 return errorbuf;
373 }
374 if (!Mod_Version)
375 {
376 snprintf(errorbuf, sizeof(errorbuf),
377 "Module is lacking Mod_Version. Perhaps a very old one you forgot to recompile?");
378 irc_dlclose(Mod);
379 remove(tmppath);
380 return errorbuf;
381 }
382 irc_dlsym(Mod, "compiler_version", compiler_version);
383 if (compiler_version && ( ((*compiler_version) & 0xffff00) != (expectedcompilerversion & 0xffff00) ) )
384 {
385 char theyhad[64], wehave[64];
386 make_compiler_string(theyhad, *compiler_version);
387 make_compiler_string(wehave, expectedcompilerversion);
388 snprintf(errorbuf, sizeof(errorbuf),
389 "Module was compiled with GCC %s, core was compiled with GCC %s. SOLUTION: Recompile your UnrealIRCd and all its modules by doing a 'make clean; ./Config -quick && make'.",
390 theyhad, wehave);
391 irc_dlclose(Mod);
392 remove(tmppath);
393 return errorbuf;
394 }
395 irc_dlsym(Mod, "Mod_Header", mod_header);
396 if (!mod_header)
397 {
398 irc_dlclose(Mod);
399 remove(tmppath);
400 return ("Unable to locate Mod_Header");
401 }
402 if (!mod_header->modversion)
403 {
404 irc_dlclose(Mod);
405 remove(tmppath);
406 return ("Lacking mod_header->modversion");
407 }
408 if (!(modsys_ver = parse_modsys_version(mod_header->modversion)))
409 {
410 snprintf(errorbuf, 1023, "Unsupported module system version '%s'",
411 mod_header->modversion);
412 irc_dlclose(Mod);
413 remove(tmppath);
414 return(errorbuf);
415 }
416 if (!mod_header->name || !mod_header->version ||
417 !mod_header->description)
418 {
419 irc_dlclose(Mod);
420 remove(tmppath);
421 return("Lacking sane header pointer");
422 }
423 if (Module_Find(mod_header->name))
424 {
425 irc_dlclose(Mod);
426 remove(tmppath);
427 return (NULL);
428 }
429 mod = (Module *)Module_make(mod_header, Mod);
430 mod->tmp_file = strdup(tmppath);
431 mod->mod_sys_version = modsys_ver;
432 mod->compiler_version = compiler_version ? *compiler_version : 0;
433
434 irc_dlsym(Mod, "Mod_Init", Mod_Init);
435 if (!Mod_Init)
436 {
437 Module_free(mod);
438 return ("Unable to locate Mod_Init");
439 }
440 irc_dlsym(Mod, "Mod_Unload", Mod_Unload);
441 if (!Mod_Unload)
442 {
443 Module_free(mod);
444 return ("Unable to locate Mod_Unload");
445 }
446 irc_dlsym(Mod, "Mod_Load", Mod_Load);
447 if (!Mod_Load)
448 {
449 Module_free(mod);
450 return ("Unable to locate Mod_Load");
451 }
452 if (Module_Depend_Resolve(mod, path) == -1)
453 {
454 Module_free(mod);
455 return ("Dependancy problem");
456 }
457 irc_dlsym(Mod, "Mod_Handle", Mod_Handle);
458 if (Mod_Handle)
459 *Mod_Handle = mod;
460 irc_dlsym(Mod, "Mod_Test", Mod_Test);
461 if (Mod_Test)
462 {
463 if (mod->mod_sys_version >= 0x320b8) {
464 if ((ret = (*Mod_Test)(&mod->modinfo)) < MOD_SUCCESS) {
465 ircsprintf(errorbuf, "Mod_Test returned %i",
466 ret);
467 /* We EXPECT the module to have cleaned up it's mess */
468 Module_free(mod);
469 return (errorbuf);
470 }
471 }
472 else {
473 if ((ret = (*Mod_Test)(0)) < MOD_SUCCESS)
474 {
475 snprintf(errorbuf, 1023, "Mod_Test returned %i",
476 ret);
477 /* We EXPECT the module to have cleaned up it's mess */
478 Module_free(mod);
479 return (errorbuf);
480 }
481 }
482 }
483 mod->flags = MODFLAG_TESTING;
484 AddListItem(mod, Modules);
485 return NULL;
486 }
487 else
488 {
489 /* Return the error .. */
490 return ((char *)irc_dlerror());
491 }
492
493 if (path != path_)
494 free(path);
495
496 #else /* !STATIC_LINKING */
497 return "We don't support dynamic linking";
498 #endif
499
500 }
501
Module_DelayChildren(Module * m)502 void Module_DelayChildren(Module *m)
503 {
504 ModuleChild *c;
505 for (c = m->children; c; c = c->next)
506 {
507 c->child->flags |= MODFLAG_DELAYED;
508 Module_DelayChildren(c->child);
509 }
510 }
511
Module_make(ModuleHeader * header,HMODULE mod)512 Module *Module_make(ModuleHeader *header,
513 #ifdef _WIN32
514 HMODULE mod
515 #else
516 void *mod
517 #endif
518 )
519 {
520 Module *modp = NULL;
521
522 modp = (Module *)MyMallocEx(sizeof(Module));
523 modp->header = header;
524 modp->dll = mod;
525 modp->flags = MODFLAG_NONE;
526 modp->options = 0;
527 modp->errorcode = MODERR_NOERROR;
528 modp->children = NULL;
529 modp->modinfo.size = sizeof(ModuleInfo);
530 modp->modinfo.module_load = 0;
531 modp->modinfo.handle = modp;
532
533 return (modp);
534 }
535
Init_all_testing_modules(void)536 void Init_all_testing_modules(void)
537 {
538
539 Module *mi, *next;
540 int ret;
541 iFP Mod_Init;
542 for (mi = Modules; mi; mi = next)
543 {
544 next = mi->next;
545 if (!(mi->flags & MODFLAG_TESTING))
546 continue;
547 irc_dlsym(mi->dll, "Mod_Init", Mod_Init);
548 if (mi->mod_sys_version >= 0x320b8) {
549 if ((ret = (*Mod_Init)(&mi->modinfo)) < MOD_SUCCESS) {
550 config_error("Error loading %s: Mod_Init returned %i",
551 mi->header->name, ret);
552 Module_free(mi);
553 continue;
554 }
555 }
556 else {
557 if ((ret = (*Mod_Init)(0)) < MOD_SUCCESS)
558 {
559 config_error("Error loading %s: Mod_Init returned %i",
560 mi->header->name, ret);
561 Module_free(mi);
562 continue;
563 }
564 }
565 mi->flags = MODFLAG_INIT;
566 }
567 }
568
Unload_all_loaded_modules(void)569 void Unload_all_loaded_modules(void)
570 {
571 Module *mi, *next;
572 ModuleChild *child, *childnext;
573 ModuleObject *objs, *objnext;
574 iFP Mod_Unload;
575 int ret;
576
577 for (mi = Modules; mi; mi = next)
578 {
579 next = mi->next;
580 if (!(mi->flags & MODFLAG_LOADED) || (mi->flags & MODFLAG_DELAYED) || (mi->options & MOD_OPT_PERM))
581 continue;
582 irc_dlsym(mi->dll, "Mod_Unload", Mod_Unload);
583 if (Mod_Unload)
584 {
585 ret = (*Mod_Unload)(0);
586 if (ret == MOD_DELAY)
587 {
588 mi->flags |= MODFLAG_DELAYED;
589 Module_DelayChildren(mi);
590 }
591 }
592 for (objs = mi->objects; objs; objs = objnext) {
593 objnext = objs->next;
594 if (objs->type == MOBJ_EVENT) {
595 LockEventSystem();
596 EventDel(objs->object.event);
597 UnlockEventSystem();
598 }
599 else if (objs->type == MOBJ_HOOK) {
600 HookDel(objs->object.hook);
601 }
602 else if (objs->type == MOBJ_COMMAND) {
603 CommandDel(objs->object.command);
604 }
605 else if (objs->type == MOBJ_HOOKTYPE) {
606 HooktypeDel(objs->object.hooktype, mi);
607 }
608 else if (objs->type == MOBJ_VERSIONFLAG) {
609 VersionflagDel(objs->object.versionflag, mi);
610 }
611 else if (objs->type == MOBJ_SNOMASK) {
612 SnomaskDel(objs->object.snomask);
613 }
614 else if (objs->type == MOBJ_UMODE) {
615 UmodeDel(objs->object.umode);
616 }
617 else if (objs->type == MOBJ_CMODE) {
618 CmodeDel(objs->object.cmode);
619 }
620 else if (objs->type == MOBJ_CMDOVERRIDE) {
621 CmdoverrideDel(objs->object.cmdoverride);
622 }
623 else if (objs->type == MOBJ_EXTBAN) {
624 ExtbanDel(objs->object.extban);
625 }
626 else if (objs->type == MOBJ_CALLBACK) {
627 CallbackDel(objs->object.callback);
628 }
629 else if (objs->type == MOBJ_EFUNCTION) {
630 EfunctionDel(objs->object.efunction);
631 }
632 else if (objs->type == MOBJ_ISUPPORT) {
633 IsupportDel(objs->object.isupport);
634 }
635 }
636 for (child = mi->children; child; child = childnext)
637 {
638 childnext = child->next;
639 DelListItem(child,mi->children);
640 MyFree(child);
641 }
642 DelListItem(mi,Modules);
643 irc_dlclose(mi->dll);
644 #ifndef DEBUGMODE
645 remove(mi->tmp_file);
646 #endif
647 MyFree(mi->tmp_file);
648 MyFree(mi);
649 }
650 }
651
Unload_all_testing_modules(void)652 void Unload_all_testing_modules(void)
653 {
654 Module *mi, *next;
655 ModuleChild *child, *childnext;
656 ModuleObject *objs, *objnext;
657
658 for (mi = Modules; mi; mi = next)
659 {
660 next = mi->next;
661 if (!(mi->flags & MODFLAG_TESTING))
662 continue;
663 for (objs = mi->objects; objs; objs = objnext) {
664 objnext = objs->next;
665 if (objs->type == MOBJ_EVENT) {
666 LockEventSystem();
667 EventDel(objs->object.event);
668 UnlockEventSystem();
669 }
670 else if (objs->type == MOBJ_HOOK) {
671 HookDel(objs->object.hook);
672 }
673 else if (objs->type == MOBJ_COMMAND) {
674 CommandDel(objs->object.command);
675 }
676 else if (objs->type == MOBJ_HOOKTYPE) {
677 HooktypeDel(objs->object.hooktype, mi);
678 }
679 else if (objs->type == MOBJ_VERSIONFLAG) {
680 VersionflagDel(objs->object.versionflag, mi);
681 }
682 else if (objs->type == MOBJ_SNOMASK) {
683 SnomaskDel(objs->object.snomask);
684 }
685 else if (objs->type == MOBJ_UMODE) {
686 UmodeDel(objs->object.umode);
687 }
688 else if (objs->type == MOBJ_CMODE) {
689 CmodeDel(objs->object.cmode);
690 }
691 else if (objs->type == MOBJ_CMDOVERRIDE) {
692 CmdoverrideDel(objs->object.cmdoverride);
693 }
694 else if (objs->type == MOBJ_EXTBAN) {
695 ExtbanDel(objs->object.extban);
696 }
697 else if (objs->type == MOBJ_CALLBACK) {
698 CallbackDel(objs->object.callback);
699 }
700 else if (objs->type == MOBJ_EFUNCTION) {
701 EfunctionDel(objs->object.efunction);
702 }
703 else if (objs->type == MOBJ_ISUPPORT) {
704 IsupportDel(objs->object.isupport);
705 }
706 }
707 for (child = mi->children; child; child = childnext)
708 {
709 childnext = child->next;
710 DelListItem(child,mi->children);
711 MyFree(child);
712 }
713 DelListItem(mi,Modules);
714 irc_dlclose(mi->dll);
715 remove(mi->tmp_file);
716 MyFree(mi->tmp_file);
717 MyFree(mi);
718 }
719 }
720
721 /*
722 * Returns -1 if you cannot unload due to children still alive
723 * Returns 1 if successful
724 */
Module_free(Module * mod)725 int Module_free(Module *mod)
726 {
727 Module *p;
728 ModuleChild *cp, *cpnext;
729 ModuleObject *objs, *next;
730 /* Do not kill parent if children still alive */
731
732 for (cp = mod->children; cp; cp = cp->next)
733 {
734 sendto_realops("Unloading child module %s",
735 cp->child->header->name);
736 Module_Unload(cp->child->header->name, 0);
737 }
738 for (objs = mod->objects; objs; objs = next) {
739 next = objs->next;
740 if (objs->type == MOBJ_EVENT) {
741 LockEventSystem();
742 EventDel(objs->object.event);
743 UnlockEventSystem();
744 }
745 else if (objs->type == MOBJ_HOOK) {
746 HookDel(objs->object.hook);
747 }
748 else if (objs->type == MOBJ_COMMAND) {
749 CommandDel(objs->object.command);
750 }
751 else if (objs->type == MOBJ_HOOKTYPE) {
752 HooktypeDel(objs->object.hooktype, mod);
753 }
754 else if (objs->type == MOBJ_VERSIONFLAG) {
755 VersionflagDel(objs->object.versionflag, mod);
756 }
757 else if (objs->type == MOBJ_SNOMASK) {
758 SnomaskDel(objs->object.snomask);
759 }
760 else if (objs->type == MOBJ_UMODE) {
761 UmodeDel(objs->object.umode);
762 }
763 else if (objs->type == MOBJ_CMODE) {
764 CmodeDel(objs->object.cmode);
765 }
766 else if (objs->type == MOBJ_CMDOVERRIDE) {
767 CmdoverrideDel(objs->object.cmdoverride);
768 }
769 else if (objs->type == MOBJ_EXTBAN) {
770 ExtbanDel(objs->object.extban);
771 }
772 else if (objs->type == MOBJ_CALLBACK) {
773 CallbackDel(objs->object.callback);
774 }
775 else if (objs->type == MOBJ_EFUNCTION) {
776 EfunctionDel(objs->object.efunction);
777 }
778 else if (objs->type == MOBJ_ISUPPORT) {
779 IsupportDel(objs->object.isupport);
780 }
781
782 }
783 for (p = Modules; p; p = p->next)
784 {
785 for (cp = p->children; cp; cp = cpnext)
786 {
787 cpnext = cp->next;
788 if (cp->child == mod)
789 {
790 DelListItem(mod, p->children);
791 MyFree(cp);
792 /* We can assume there can be only one. */
793 break;
794 }
795 }
796 }
797 DelListItem(mod, Modules);
798 irc_dlclose(mod->dll);
799 MyFree(mod->tmp_file);
800 MyFree(mod);
801 return 1;
802 }
803
804 /*
805 * Module_Unload ()
806 * char *name Internal module name
807 * int unload If /module unload
808 * Returns:
809 * -1 Not able to locate module, severe failure, anything
810 * 1 Module unloaded
811 * 2 Module wishes delayed unloading, has placed event
812 */
Module_Unload(char * name,int unload)813 int Module_Unload(char *name, int unload)
814 {
815 Module *m;
816 int (*Mod_Unload)();
817 int ret;
818 for (m = Modules; m; m = m->next)
819 {
820 if (!strcmp(m->header->name, name))
821 {
822 break;
823 }
824 }
825 if (!m)
826 return -1;
827 irc_dlsym(m->dll, "Mod_Unload", Mod_Unload);
828 if (!Mod_Unload)
829 {
830 return -1;
831 }
832 ret = (*Mod_Unload)(unload);
833 if (ret == MOD_DELAY)
834 {
835 m->flags |= MODFLAG_DELAYED;
836 Module_DelayChildren(m);
837 return 2;
838 }
839 if (ret == MOD_FAILED)
840 {
841 return -1;
842 }
843 /* No more pain detected, let's unload */
844 DelListItem(m, Modules);
845 Module_free(m);
846 return 1;
847 }
848
Module_SymEx(HMODULE mod,char * name)849 vFP Module_SymEx(
850 #ifdef _WIN32
851 HMODULE mod
852 #else
853 void *mod
854 #endif
855 , char *name)
856 {
857 #ifndef STATIC_LINKING
858 vFP fp;
859
860 if (!name)
861 return NULL;
862
863 irc_dlsym(mod, name, fp);
864 if (fp)
865 return (fp);
866 return NULL;
867 #endif
868
869 }
870
Module_Sym(char * name)871 vFP Module_Sym(char *name)
872 {
873 #ifndef STATIC_LINKING
874 vFP fp;
875 Module *mi;
876
877 if (!name)
878 return NULL;
879
880 /* Run through all modules and check for symbols */
881 for (mi = Modules; mi; mi = mi->next)
882 {
883 if (!(mi->flags & MODFLAG_TESTING) || (mi->flags & MODFLAG_DELAYED))
884 continue;
885 irc_dlsym(mi->dll, name, fp);
886 if (fp)
887 return (fp);
888 }
889 return NULL;
890 #endif
891 }
892
Module_SymX(char * name,Module ** mptr)893 vFP Module_SymX(char *name, Module **mptr)
894 {
895 #ifndef STATIC_LINKING
896 vFP fp;
897 Module *mi;
898
899 if (!name)
900 return NULL;
901
902 /* Run through all modules and check for symbols */
903 for (mi = Modules; mi; mi = mi->next)
904 {
905 if (!(mi->flags & MODFLAG_TESTING) || (mi->flags & MODFLAG_DELAYED))
906 continue;
907 irc_dlsym(mi->dll, name, fp);
908 if (fp)
909 {
910 *mptr = mi;
911 return (fp);
912 }
913 }
914 *mptr = NULL;
915 return NULL;
916 #endif
917 }
918
919
920
921
module_loadall(int module_load)922 void module_loadall(int module_load)
923 {
924 #ifndef STATIC_LINKING
925 iFP fp;
926 Module *mi, *next;
927
928 if (!loop.ircd_booted)
929 {
930 sendto_realops("Ehh, !loop.ircd_booted in module_loadall()");
931 return ;
932 }
933 /* Run through all modules and check for module load */
934 for (mi = Modules; mi; mi = next)
935 {
936 next = mi->next;
937 if (mi->flags & MODFLAG_LOADED)
938 continue;
939 irc_dlsym(mi->dll, "Mod_Load", fp);
940 /* Call the module_load */
941 if ((*fp)(module_load) != MOD_SUCCESS)
942 {
943 config_status("cannot load module %s", mi->header->name);
944 Module_free(mi);
945 }
946 else
947 mi->flags = MODFLAG_LOADED;
948 }
949 #endif
950 }
951
Module_IsAlreadyChild(Module * parent,Module * child)952 inline int Module_IsAlreadyChild(Module *parent, Module *child)
953 {
954 ModuleChild *mcp;
955
956 for (mcp = parent->children; mcp; mcp = mcp->next)
957 {
958 if (mcp->child == child)
959 return 1;
960 }
961 return 0;
962 }
963
Module_AddAsChild(Module * parent,Module * child)964 inline void Module_AddAsChild(Module *parent, Module *child)
965 {
966 ModuleChild *childp = NULL;
967
968 childp = (ModuleChild *) MyMallocEx(sizeof(ModuleChild));
969 childp->child = child;
970 AddListItem(childp, parent->children);
971 }
972
Module_Depend_Resolve(Module * p,char * path)973 int Module_Depend_Resolve(Module *p, char *path)
974 {
975 Mod_SymbolDepTable *d = p->header->symdep;
976 Module *parental = NULL;
977
978 if (d == NULL)
979 return 0;
980 #ifndef STATIC_LINKING
981 while (d->pointer)
982 {
983 if ((*(d->pointer) = Module_SymEx(p->dll, d->symbol)))
984 {
985 d++;
986 continue;
987 }
988 *(d->pointer) = Module_SymX(d->symbol, &parental);
989 if (!*(d->pointer))
990 {
991 /* If >= 3.2.3 */
992 if (p->mod_sys_version >= 0x32300)
993 {
994 char tmppath[PATH_MAX], curpath[PATH_MAX];
995
996 unreal_getpathname(path, curpath);
997 snprintf(tmppath, PATH_MAX, "%s/%s.%s", curpath, d->module,
998 MOD_EXTENSION);
999 config_progress("Unable to resolve symbol %s, attempting to load %s to find it", d->symbol, tmppath);
1000 Module_Create(tmppath);
1001 }
1002 else
1003 {
1004 config_progress("Unable to resolve symbol %s, attempting to load %s to find it", d->symbol, d->module);
1005 Module_Create(d->module);
1006 }
1007 *(d->pointer) = Module_SymX(d->symbol, &parental);
1008 if (!*(d->pointer)) {
1009 config_progress("module dependancy error: cannot resolve symbol %s",
1010 d->symbol);
1011 return -1;
1012 }
1013
1014 }
1015 if (!Module_IsAlreadyChild(parental, p))
1016 Module_AddAsChild(parental, p);
1017 d++;
1018 }
1019 return 0;
1020 #else
1021 while (d->pointer)
1022 {
1023 *((vFP *)d->pointer) = (vFP) d->realfunc;
1024 d++;
1025 }
1026 #endif
1027 }
1028
1029 /* m_module.
1030 * by Stskeeps, codemastr, Syzop.
1031 * Changed it so it's now public for users too, as quite some people
1032 * (and users) requested they should have the right to see what kind
1033 * of weird modules are loaded on the server, especially since people
1034 * like to load spy modules these days.
1035 * I do not consider this sensitive information, but just in case
1036 * I stripped the version string for non-admins (eg: normal users). -- Syzop
1037 */
m_module(aClient * cptr,aClient * sptr,int parc,char * parv[])1038 int m_module(aClient *cptr, aClient *sptr, int parc, char *parv[])
1039 {
1040 Module *mi;
1041 int i;
1042 char tmp[1024], *p;
1043 aCommand *mptr;
1044 #ifdef DEBUGMODE
1045 Efunction *e;
1046 #endif
1047
1048 /* Opers can do /module <servername> */
1049 if ((parc > 1) && (hunt_server_token(cptr, sptr, MSG_MODULE, TOK_MODULE, ":%s", 1, parc,
1050 parv) != HUNTED_ISME))
1051 return 0;
1052 if (!Modules)
1053 {
1054 sendto_one(sptr, ":%s NOTICE %s :*** No modules loaded", me.name, sptr->name);
1055 return 1;
1056 }
1057
1058 for (mi = Modules; mi; mi = mi->next)
1059 {
1060 tmp[0] = '\0';
1061 if (mi->flags & MODFLAG_DELAYED)
1062 strcat(tmp, "[Unloading] ");
1063 if (mi->options & MOD_OPT_PERM)
1064 strcat(tmp, "[PERM] ");
1065 if (!(mi->options & MOD_OPT_OFFICIAL))
1066 strcat(tmp, "[3RD] ");
1067 if (!IsOper(sptr))
1068 sendto_one(sptr, ":%s NOTICE %s :*** %s (%s)%s", me.name, sptr->name,
1069 mi->header->name, mi->header->description,
1070 mi->options & MOD_OPT_OFFICIAL ? "" : " [3RD]");
1071 else
1072 sendto_one(sptr, ":%s NOTICE %s :*** %s - %s (%s) %s", me.name, sptr->name,
1073 mi->header->name, mi->header->version, mi->header->description, tmp);
1074 }
1075
1076 if (!IsOper(sptr))
1077 return 0;
1078
1079 tmp[0] = '\0';
1080 p = tmp;
1081 for (i=0; i < MAXHOOKTYPES; i++)
1082 {
1083 if (!Hooks[i])
1084 continue;
1085 sprintf(p, "%d ", i);
1086 p += strlen(p);
1087 if (p > tmp+380)
1088 {
1089 sendto_one(sptr, ":%s NOTICE %s :Hooks: %s", me.name, sptr->name, tmp);
1090 tmp[0] = '\0';
1091 p = tmp;
1092 }
1093 }
1094 sendto_one(sptr, ":%s NOTICE %s :Hooks: %s ", me.name, sptr->name, tmp);
1095
1096 tmp[0] = '\0';
1097 p = tmp;
1098 for (i=0; i < 256; i++)
1099 {
1100 for (mptr = CommandHash[i]; mptr; mptr = mptr->next)
1101 if (mptr->overriders)
1102 {
1103 sprintf(p, "%s ", mptr->cmd);
1104 p += strlen(p);
1105 if (p > tmp+380)
1106 {
1107 sendto_one(sptr, ":%s NOTICE %s :Override: %s", me.name, sptr->name, tmp);
1108 tmp[0] = '\0';
1109 p = tmp;
1110 }
1111 }
1112 }
1113 sendto_one(sptr, ":%s NOTICE %s :Override: %s", me.name, sptr->name, tmp);
1114
1115 #ifdef DEBUGMODE
1116 sendnotice(sptr, "Efunctions dump:");
1117 for (i=0; i < MAXEFUNCTIONS; i++)
1118 if ((e = Efunctions[i]))
1119 {
1120 sendnotice(sptr, "type=%d, name=%s, pointer=%p %s, owner=%s",
1121 e->type,
1122 efunction_table[e->type].name ? efunction_table[e->type].name : "<null>",
1123 e->func.voidfunc,
1124 *efunction_table[e->type].funcptr == e->func.voidfunc ? " [ACTIVE]" : "",
1125 e->owner ? e->owner->header->name : "<null>");
1126 }
1127 #endif
1128
1129 return 1;
1130 }
1131
HooktypeFind(char * string)1132 Hooktype *HooktypeFind(char *string) {
1133 Hooktype *hooktype;
1134 for (hooktype = Hooktypes; hooktype->string ;hooktype++) {
1135 if (!stricmp(hooktype->string, string))
1136 return hooktype;
1137 }
1138 return NULL;
1139 }
1140
VersionflagFind(char flag)1141 Versionflag *VersionflagFind(char flag)
1142 {
1143 Versionflag *vflag;
1144 for (vflag = Versionflags; vflag; vflag = vflag->next)
1145 {
1146 if (vflag->flag == flag)
1147 return vflag;
1148 }
1149 return NULL;
1150 }
1151
VersionflagAdd(Module * module,char flag)1152 Versionflag *VersionflagAdd(Module *module, char flag)
1153 {
1154 Versionflag *vflag;
1155 ModuleChild *parent;
1156 if ((vflag = VersionflagFind(flag)))
1157 {
1158 ModuleChild *child;
1159 for (child = vflag->parents; child; child = child->next) {
1160 if (child->child == module)
1161 break;
1162 }
1163 if (!child)
1164 {
1165 parent = MyMallocEx(sizeof(ModuleChild));
1166 parent->child = module;
1167 if (module) {
1168 ModuleObject *vflagobj;
1169 vflagobj = MyMallocEx(sizeof(ModuleObject));
1170 vflagobj->type = MOBJ_VERSIONFLAG;
1171 vflagobj->object.versionflag = vflag;
1172 AddListItem(vflagobj, module->objects);
1173 module->errorcode = MODERR_NOERROR;
1174 }
1175 AddListItem(parent,vflag->parents);
1176 }
1177 return vflag;
1178 }
1179 vflag = MyMallocEx(sizeof(Versionflag));
1180 vflag->flag = flag;
1181 parent = MyMallocEx(sizeof(ModuleChild));
1182 parent->child = module;
1183 if (module)
1184 {
1185 ModuleObject *vflagobj;
1186 vflagobj = MyMallocEx(sizeof(ModuleObject));
1187 vflagobj->type = MOBJ_VERSIONFLAG;
1188 vflagobj->object.versionflag = vflag;
1189 AddListItem(vflagobj, module->objects);
1190 module->errorcode = MODERR_NOERROR;
1191 }
1192 flag_add(flag);
1193 AddListItem(parent,vflag->parents);
1194 AddListItem(vflag, Versionflags);
1195 return vflag;
1196 }
1197
VersionflagDel(Versionflag * vflag,Module * module)1198 void VersionflagDel(Versionflag *vflag, Module *module)
1199 {
1200 ModuleChild *owner;
1201 if (!vflag)
1202 return;
1203
1204 for (owner = vflag->parents; owner; owner = owner->next)
1205 {
1206 if (owner->child == module)
1207 {
1208 DelListItem(owner,vflag->parents);
1209 MyFree(owner);
1210 break;
1211 }
1212 }
1213 if (module)
1214 {
1215 ModuleObject *objs;
1216 for (objs = module->objects; objs; objs = objs->next) {
1217 if (objs->type == MOBJ_VERSIONFLAG && objs->object.versionflag == vflag) {
1218 DelListItem(objs,module->objects);
1219 MyFree(objs);
1220 break;
1221 }
1222 }
1223 }
1224 if (!vflag->parents)
1225 {
1226 flag_del(vflag->flag);
1227 DelListItem(vflag, Versionflags);
1228 MyFree(vflag);
1229 }
1230 }
1231
HooktypeAdd(Module * module,char * string,int * type)1232 Hooktype *HooktypeAdd(Module *module, char *string, int *type) {
1233 Hooktype *hooktype;
1234 int i;
1235 ModuleChild *parent;
1236 ModuleObject *hooktypeobj;
1237 if ((hooktype = HooktypeFind(string))) {
1238 ModuleChild *child;
1239 for (child = hooktype->parents; child; child = child->next) {
1240 if (child->child == module)
1241 break;
1242 }
1243 if (!child) {
1244 parent = MyMallocEx(sizeof(ModuleChild));
1245 parent->child = module;
1246 if (module) {
1247 hooktypeobj = MyMallocEx(sizeof(ModuleObject));
1248 hooktypeobj->type = MOBJ_HOOKTYPE;
1249 hooktypeobj->object.hooktype = hooktype;
1250 AddListItem(hooktypeobj, module->objects);
1251 module->errorcode = MODERR_NOERROR;
1252 }
1253 AddListItem(parent,hooktype->parents);
1254 }
1255 *type = hooktype->id;
1256 return hooktype;
1257 }
1258 for (hooktype = Hooktypes, i = 0; hooktype->string; hooktype++, i++) ;
1259
1260 if (i >= 39)
1261 {
1262 if (module)
1263 module->errorcode = MODERR_NOSPACE;
1264 return NULL;
1265 }
1266
1267 Hooktypes[i].id = i+41;
1268 Hooktypes[i].string = strdup(string);
1269 parent = MyMallocEx(sizeof(ModuleChild));
1270 parent->child = module;
1271 if (module) {
1272 hooktypeobj = MyMallocEx(sizeof(ModuleObject));
1273 hooktypeobj->type = MOBJ_HOOKTYPE;
1274 hooktypeobj->object.hooktype = &Hooktypes[i];
1275 AddListItem(hooktypeobj,module->objects);
1276 module->errorcode = MODERR_NOERROR;
1277 }
1278 AddListItem(parent,Hooktypes[i].parents);
1279 *type = i+41;
1280 return &Hooktypes[i];
1281 }
1282
HooktypeDel(Hooktype * hooktype,Module * module)1283 void HooktypeDel(Hooktype *hooktype, Module *module) {
1284 ModuleChild *child;
1285 ModuleObject *objs;
1286 for (child = hooktype->parents; child; child = child->next) {
1287 if (child->child == module) {
1288 DelListItem(child,hooktype->parents);
1289 MyFree(child);
1290 break;
1291 }
1292 }
1293 if (module) {
1294 for (objs = module->objects; objs; objs = objs->next) {
1295 if (objs->type == MOBJ_HOOKTYPE && objs->object.hooktype == hooktype) {
1296 DelListItem(objs,module->objects);
1297 MyFree(objs);
1298 break;
1299 }
1300 }
1301 }
1302 if (!hooktype->parents) {
1303 MyFree(hooktype->string);
1304 hooktype->string = NULL;
1305 hooktype->id = 0;
1306 hooktype->parents = NULL;
1307 }
1308 }
1309
1310
HookAddMain(Module * module,int hooktype,int (* func)(),void (* vfunc)(),char * (* cfunc)())1311 Hook *HookAddMain(Module *module, int hooktype, int (*func)(), void (*vfunc)(), char *(*cfunc)())
1312 {
1313 Hook *p;
1314
1315 p = (Hook *) MyMallocEx(sizeof(Hook));
1316 if (func)
1317 p->func.intfunc = func;
1318 if (vfunc)
1319 p->func.voidfunc = vfunc;
1320 if (cfunc)
1321 p->func.pcharfunc = cfunc;
1322 p->type = hooktype;
1323 p->owner = module;
1324 AddListItem(p, Hooks[hooktype]);
1325 if (module) {
1326 ModuleObject *hookobj = (ModuleObject *)MyMallocEx(sizeof(ModuleObject));
1327 hookobj->object.hook = p;
1328 hookobj->type = MOBJ_HOOK;
1329 AddListItem(hookobj, module->objects);
1330 module->errorcode = MODERR_NOERROR;
1331 }
1332 return p;
1333 }
1334
HookDel(Hook * hook)1335 Hook *HookDel(Hook *hook)
1336 {
1337 Hook *p, *q;
1338 for (p = Hooks[hook->type]; p; p = p->next) {
1339 if (p == hook) {
1340 q = p->next;
1341 DelListItem(p, Hooks[hook->type]);
1342 if (p->owner) {
1343 ModuleObject *hookobj;
1344 for (hookobj = p->owner->objects; hookobj; hookobj = hookobj->next) {
1345 if (hookobj->type == MOBJ_HOOK && hookobj->object.hook == p) {
1346 DelListItem(hookobj, hook->owner->objects);
1347 MyFree(hookobj);
1348 break;
1349 }
1350 }
1351 }
1352 MyFree(p);
1353 return q;
1354 }
1355 }
1356 return NULL;
1357 }
1358
CallbackAddMain(Module * module,int cbtype,int (* func)(),void (* vfunc)(),char * (* cfunc)())1359 Callback *CallbackAddMain(Module *module, int cbtype, int (*func)(), void (*vfunc)(), char *(*cfunc)())
1360 {
1361 Callback *p;
1362
1363 p = (Callback *) MyMallocEx(sizeof(Callback));
1364 if (func)
1365 p->func.intfunc = func;
1366 if (vfunc)
1367 p->func.voidfunc = vfunc;
1368 if (cfunc)
1369 p->func.pcharfunc = cfunc;
1370 p->type = cbtype;
1371 p->owner = module;
1372 AddListItem(p, Callbacks[cbtype]);
1373 if (module) {
1374 ModuleObject *cbobj = (ModuleObject *)MyMallocEx(sizeof(ModuleObject));
1375 cbobj->object.callback = p;
1376 cbobj->type = MOBJ_CALLBACK;
1377 AddListItem(cbobj, module->objects);
1378 module->errorcode = MODERR_NOERROR;
1379 }
1380 return p;
1381 }
1382
CallbackDel(Callback * cb)1383 Callback *CallbackDel(Callback *cb)
1384 {
1385 Callback *p, *q;
1386 for (p = Callbacks[cb->type]; p; p = p->next) {
1387 if (p == cb) {
1388 q = p->next;
1389 DelListItem(p, Callbacks[cb->type]);
1390 if (RCallbacks[cb->type] == p)
1391 RCallbacks[cb->type] = NULL;
1392 if (p->owner) {
1393 ModuleObject *cbobj;
1394 for (cbobj = p->owner->objects; cbobj; cbobj = cbobj->next) {
1395 if ((cbobj->type == MOBJ_CALLBACK) && (cbobj->object.callback == p)) {
1396 DelListItem(cbobj, cb->owner->objects);
1397 MyFree(cbobj);
1398 break;
1399 }
1400 }
1401 }
1402 MyFree(p);
1403 return q;
1404 }
1405 }
1406 return NULL;
1407 }
1408
EfunctionAddMain(Module * module,int eftype,int (* func)(),void (* vfunc)(),void * (* pvfunc)(),char * (* cfunc)())1409 Efunction *EfunctionAddMain(Module *module, int eftype, int (*func)(), void (*vfunc)(), void *(*pvfunc)(), char *(*cfunc)())
1410 {
1411 Efunction *p;
1412
1413 if (!module || !(module->options & MOD_OPT_OFFICIAL))
1414 {
1415 module->errorcode = MODERR_INVALID;
1416 return NULL;
1417 }
1418
1419 p = (Efunction *) MyMallocEx(sizeof(Efunction));
1420 if (func)
1421 p->func.intfunc = func;
1422 if (vfunc)
1423 p->func.voidfunc = vfunc;
1424 if (pvfunc)
1425 p->func.pvoidfunc = pvfunc;
1426 if (cfunc)
1427 p->func.pcharfunc = cfunc;
1428 p->type = eftype;
1429 p->owner = module;
1430 AddListItem(p, Efunctions[eftype]);
1431 if (module) {
1432 ModuleObject *cbobj = (ModuleObject *)MyMallocEx(sizeof(ModuleObject));
1433 cbobj->object.efunction = p;
1434 cbobj->type = MOBJ_EFUNCTION;
1435 AddListItem(cbobj, module->objects);
1436 module->errorcode = MODERR_NOERROR;
1437 }
1438 return p;
1439 }
1440
EfunctionDel(Efunction * cb)1441 Efunction *EfunctionDel(Efunction *cb)
1442 {
1443 Efunction *p, *q;
1444 for (p = Efunctions[cb->type]; p; p = p->next) {
1445 if (p == cb) {
1446 q = p->next;
1447 DelListItem(p, Efunctions[cb->type]);
1448 if (*efunction_table[cb->type].funcptr == p)
1449 *efunction_table[cb->type].funcptr = NULL;
1450 if (p->owner) {
1451 ModuleObject *cbobj;
1452 for (cbobj = p->owner->objects; cbobj; cbobj = cbobj->next) {
1453 if ((cbobj->type == MOBJ_EFUNCTION) && (cbobj->object.efunction == p)) {
1454 DelListItem(cbobj, cb->owner->objects);
1455 MyFree(cbobj);
1456 break;
1457 }
1458 }
1459 }
1460 MyFree(p);
1461 return q;
1462 }
1463 }
1464 return NULL;
1465 }
1466
CmdoverrideAdd(Module * module,char * name,iFP function)1467 Cmdoverride *CmdoverrideAdd(Module *module, char *name, iFP function)
1468 {
1469 aCommand *p;
1470 Cmdoverride *ovr;
1471
1472 if (!(p = find_Command_simple(name)))
1473 {
1474 if (module)
1475 module->errorcode = MODERR_NOTFOUND;
1476 return NULL;
1477 }
1478 for (ovr=p->overriders; ovr; ovr=ovr->next)
1479 {
1480 if ((ovr->owner == module) && (ovr->func == function))
1481 {
1482 if (module)
1483 module->errorcode = MODERR_EXISTS;
1484 return NULL;
1485 }
1486 }
1487 ovr = MyMallocEx(sizeof(Cmdoverride));
1488 ovr->func = function;
1489 ovr->owner = module; /* TODO: module objects */
1490 if (module)
1491 {
1492 ModuleObject *cmdoverobj = MyMallocEx(sizeof(ModuleObject));
1493 cmdoverobj->type = MOBJ_CMDOVERRIDE;
1494 cmdoverobj->object.cmdoverride = ovr;
1495 AddListItem(cmdoverobj, module->objects);
1496 module->errorcode = MODERR_NOERROR;
1497 }
1498 ovr->command = p;
1499 if (!p->overriders)
1500 p->overridetail = ovr;
1501 AddListItem(ovr, p->overriders);
1502 if (p->friend)
1503 {
1504 if (!p->friend->overriders)
1505 p->friend->overridetail = ovr;
1506 AddListItem(ovr, p->friend->overriders);
1507 }
1508 return ovr;
1509 }
1510
CmdoverrideDel(Cmdoverride * cmd)1511 void CmdoverrideDel(Cmdoverride *cmd)
1512 {
1513 if (!cmd->next)
1514 cmd->command->overridetail = cmd->prev;
1515 DelListItem(cmd, cmd->command->overriders);
1516 if (!cmd->command->overriders)
1517 cmd->command->overridetail = NULL;
1518 if (cmd->command->friend)
1519 {
1520 if (!cmd->prev)
1521 cmd->command->friend->overridetail = NULL;
1522 DelListItem(cmd, cmd->command->friend->overriders);
1523 }
1524 if (cmd->owner)
1525 {
1526 ModuleObject *obj;
1527 for (obj = cmd->owner->objects; obj; obj = obj->next)
1528 {
1529 if (obj->type != MOBJ_CMDOVERRIDE)
1530 continue;
1531 if (obj->object.cmdoverride == cmd)
1532 {
1533 DelListItem(obj, cmd->owner->objects);
1534 MyFree(obj);
1535 break;
1536 }
1537 }
1538 }
1539 MyFree(cmd);
1540 }
1541
CallCmdoverride(Cmdoverride * ovr,aClient * cptr,aClient * sptr,int parc,char * parv[])1542 int CallCmdoverride(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[])
1543 {
1544 if (ovr->prev)
1545 return ovr->prev->func(ovr->prev, cptr, sptr, parc, parv);
1546 return ovr->command->func(cptr, sptr, parc, parv);
1547 }
1548
EVENT(e_unload_module_delayed)1549 EVENT(e_unload_module_delayed)
1550 {
1551 char *name = strdup(data);
1552 int i;
1553 i = Module_Unload(name, 0);
1554 if (i == -1)
1555 {
1556 sendto_realops("Failed to unload '%s'", name);
1557 }
1558 if (i == 1)
1559 {
1560 sendto_realops("Unloaded module %s", name);
1561 }
1562 free(name);
1563 return;
1564 }
1565
unload_all_modules(void)1566 void unload_all_modules(void)
1567 {
1568 Module *m;
1569 int (*Mod_Unload)();
1570 for (m = Modules; m; m = m->next)
1571 {
1572 irc_dlsym(m->dll, "Mod_Unload", Mod_Unload);
1573 if (Mod_Unload)
1574 (*Mod_Unload)(0);
1575 remove(m->tmp_file);
1576 }
1577 }
1578
ModuleSetOptions(Module * module,unsigned int options)1579 unsigned int ModuleSetOptions(Module *module, unsigned int options)
1580 {
1581 unsigned int oldopts = module->options;
1582
1583 module->options = options;
1584 return oldopts;
1585 }
1586
ModuleGetOptions(Module * module)1587 unsigned int ModuleGetOptions(Module *module)
1588 {
1589 return module->options;
1590 }
1591
ModuleGetError(Module * module)1592 unsigned int ModuleGetError(Module *module)
1593 {
1594 return module->errorcode;
1595 }
1596
1597 static const char *module_error_str[] = {
1598 "No error",
1599 "Object already exists",
1600 "No space available",
1601 "Invalid parameter(s)",
1602 "Object was not found"
1603 };
1604
ModuleGetErrorStr(Module * module)1605 const char *ModuleGetErrorStr(Module *module)
1606 {
1607 if (module->errorcode >= sizeof(module_error_str)/sizeof(module_error_str[0]))
1608 return NULL;
1609
1610 return module_error_str[module->errorcode];
1611 }
1612
num_callbacks(int cbtype)1613 static int num_callbacks(int cbtype)
1614 {
1615 Callback *e;
1616 int cnt = 0;
1617
1618 for (e = Callbacks[cbtype]; e; e = e->next)
1619 if (!e->willberemoved)
1620 cnt++;
1621
1622 return cnt;
1623 }
1624
1625 /** Ensure that all required callbacks are in place and meet
1626 * all specified requirements (eg: a cloaking module should
1627 * be loaded).
1628 */
callbacks_check(void)1629 int callbacks_check(void)
1630 {
1631 int i;
1632
1633 if ((!num_callbacks(CALLBACKTYPE_CLOAK) && !num_callbacks(CALLBACKTYPE_CLOAK_EX)) || !num_callbacks(CALLBACKTYPE_CLOAKKEYCSUM))
1634 {
1635 #ifndef _WIN32
1636 config_error("ERROR: No cloaking module loaded. (hint: you probably want to load cloak.so)");
1637 #else
1638 config_error("ERROR: No cloaking module loaded. (hint: you probably want to load modules\\cloak.dll)");
1639 #endif
1640 return -1;
1641 }
1642
1643 for (i=0; i < MAXCALLBACKS; i++)
1644 {
1645 if (num_callbacks(i) > 1)
1646 {
1647 config_error("ERROR: Multiple callbacks loaded for type %d. "
1648 "Make sure you only load 1 module of 1 type (eg: only 1 cloaking module)",
1649 i); /* TODO: make more clear? */
1650 return -1;
1651 }
1652 }
1653
1654 return 0;
1655 }
1656
callbacks_switchover(void)1657 void callbacks_switchover(void)
1658 {
1659 Callback *e;
1660 int i;
1661
1662 /* Now set the real callback, and tag the new one
1663 * as 'willberemoved' if needed.
1664 */
1665
1666 for (i=0; i < MAXCALLBACKS; i++)
1667 for (e = Callbacks[i]; e; e = e->next)
1668 if (!e->willberemoved)
1669 {
1670 RCallbacks[i] = e; /* This is the new one. */
1671 if (!(e->owner->options & MOD_OPT_PERM))
1672 e->willberemoved = 1;
1673 break;
1674 }
1675 }
1676
num_efunctions(int eftype)1677 static int num_efunctions(int eftype)
1678 {
1679 Efunction *e;
1680 int cnt = 0;
1681
1682 #ifdef DEBUGMODE
1683 if ((eftype < 0) || (eftype >= MAXEFUNCTIONS))
1684 abort();
1685 #endif
1686
1687 for (e = Efunctions[eftype]; e; e = e->next)
1688 if (!e->willberemoved)
1689 cnt++;
1690
1691 return cnt;
1692 }
1693
1694
1695 /** Ensure that all efunctions are present. */
efunctions_check(void)1696 int efunctions_check(void)
1697 {
1698 int i, n, errors=0;
1699
1700 for (i=0; i < MAXEFUNCTIONS; i++)
1701 if (efunction_table[i].name)
1702 {
1703 n = num_efunctions(i);
1704 if ((n != 1) && (errors > 10))
1705 {
1706 config_error("[--efunction errors truncated to prevent flooding--]");
1707 break;
1708 }
1709 if (n < 1)
1710 {
1711 config_error("ERROR: efunction '%s' not found, you probably did not "
1712 "load commands.so properly (or not all required m_* modules)",
1713 efunction_table[i].name);
1714 errors++;
1715 } else
1716 if (n > 1)
1717 {
1718 config_error("ERROR: efunction '%s' was found %d times, perhaps you "
1719 "loaded commands.so twice or commands.so and a/the m_*.so module(s)",
1720 efunction_table[i].name, n);
1721 errors++;
1722 }
1723 }
1724 return errors ? -1 : 0;
1725 }
1726
efunctions_switchover(void)1727 void efunctions_switchover(void)
1728 {
1729 Efunction *e;
1730 int i;
1731
1732 /* Now set the real efunction, and tag the new one
1733 * as 'willberemoved' if needed.
1734 */
1735
1736 for (i=0; i < MAXEFUNCTIONS; i++)
1737 for (e = Efunctions[i]; e; e = e->next)
1738 if (!e->willberemoved)
1739 {
1740 *efunction_table[i].funcptr = e->func.voidfunc; /* This is the new one. */
1741 if (!(e->owner->options & MOD_OPT_PERM))
1742 e->willberemoved = 1;
1743 break;
1744 }
1745 }
1746
1747 #ifdef _WIN32
our_dlerror(void)1748 const char *our_dlerror(void)
1749 {
1750 static char errbuf[513];
1751 DWORD err = GetLastError();
1752 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
1753 0, errbuf, 512, NULL);
1754 if (err == 126) /* FIXME: find the correct code for 126 */
1755 strlcat(errbuf, " This could be because the DLL depends on another DLL, for example if you "
1756 "are trying to load a 3rd party module which was compiled with a different compiler version.",
1757 sizeof(errbuf));
1758 return errbuf;
1759 }
1760 #endif
1761