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 *)&register_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