1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2013, 2015, 2019-2020 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2013 Adam <Adam@anope.org>
6  *   Copyright (C) 2012-2013, 2015 Attila Molnar <attilamolnar@hush.com>
7  *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
8  *   Copyright (C) 2012 ChrisTX <xpipe@hotmail.de>
9  *   Copyright (C) 2010 Craig Edwards <brain@inspircd.org>
10  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
11  *
12  * This file is part of InspIRCd.  InspIRCd is free software: you can
13  * redistribute it and/or modify it under the terms of the GNU General Public
14  * License as published by the Free Software Foundation, version 2.
15  *
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 
26 #include "inspircd.h"
27 #include "exitcodes.h"
28 #include <iostream>
29 
Load(const std::string & modname,bool defer)30 bool ModuleManager::Load(const std::string& modname, bool defer)
31 {
32 	/* Don't allow people to specify paths for modules, it doesn't work as expected */
33 	if (modname.find('/') != std::string::npos)
34 	{
35 		LastModuleError = "You can't load modules with a path: " + modname;
36 		return false;
37 	}
38 
39 	const std::string filename = ExpandModName(modname);
40 	const std::string moduleFile = ServerInstance->Config->Paths.PrependModule(filename);
41 
42 	if (!FileSystem::FileExists(moduleFile))
43 	{
44 		LastModuleError = "Module file could not be found: " + filename;
45 		ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
46 		return false;
47 	}
48 
49 	if (Modules.find(filename) != Modules.end())
50 	{
51 		LastModuleError = "Module " + filename + " is already loaded, cannot load a module twice!";
52 		ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
53 		return false;
54 	}
55 
56 	Module* newmod = NULL;
57 	DLLManager* newhandle = new DLLManager(moduleFile.c_str());
58 	ServiceList newservices;
59 	if (!defer)
60 		this->NewServices = &newservices;
61 
62 	try
63 	{
64 		newmod = newhandle->CallInit();
65 		this->NewServices = NULL;
66 
67 		if (newmod)
68 		{
69 			newmod->ModuleSourceFile = filename;
70 			newmod->ModuleDLLManager = newhandle;
71 			Modules[filename] = newmod;
72 			const char* version = newhandle->GetVersion();
73 			if (!version)
74 				version = "unknown";
75 			if (defer)
76 			{
77 				ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)",
78 					filename.c_str(), version);
79 			}
80 			else
81 			{
82 				ConfigStatus confstatus;
83 
84 				AttachAll(newmod);
85 				AddServices(newservices);
86 				newmod->init();
87 				newmod->ReadConfig(confstatus);
88 
89 				Version v = newmod->GetVersion();
90 				ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)%s",
91 					filename.c_str(), version, (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]"));
92 			}
93 		}
94 		else
95 		{
96 			LastModuleError = "Unable to load " + filename + ": " + newhandle->LastError();
97 			ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
98 			delete newhandle;
99 			return false;
100 		}
101 	}
102 	catch (CoreException& modexcept)
103 	{
104 		this->NewServices = NULL;
105 
106 		// failure in module constructor
107 		if (newmod)
108 		{
109 			DoSafeUnload(newmod);
110 			ServerInstance->GlobalCulls.AddItem(newhandle);
111 		}
112 		else
113 			delete newhandle;
114 		LastModuleError = "Unable to load " + filename + ": " + modexcept.GetReason();
115 		ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
116 		return false;
117 	}
118 
119 	if (defer)
120 		return true;
121 
122 	FOREACH_MOD(OnLoadModule, (newmod));
123 	PrioritizeHooks();
124 	ServerInstance->ISupport.Build();
125 	return true;
126 }
127 
128 /* We must load the modules AFTER initializing the socket engine, now */
LoadCoreModules(std::map<std::string,ServiceList> & servicemap)129 void ModuleManager::LoadCoreModules(std::map<std::string, ServiceList>& servicemap)
130 {
131 	std::cout << "Loading core modules " << std::flush;
132 
133 	std::vector<std::string> files;
134 	if (!FileSystem::GetFileList(ServerInstance->Config->Paths.Module, files, "core_*.so"))
135 	{
136 		std::cout << "failed!" << std::endl;
137 		ServerInstance->Exit(EXIT_STATUS_MODULE);
138 	}
139 
140 	for (std::vector<std::string>::const_iterator iter = files.begin(); iter != files.end(); ++iter)
141 	{
142 		std::cout << "." << std::flush;
143 
144 		const std::string& name = *iter;
145 		this->NewServices = &servicemap[name];
146 
147 		if (!Load(name, true))
148 		{
149 			ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, this->LastError());
150 			std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl;
151 			ServerInstance->Exit(EXIT_STATUS_MODULE);
152 		}
153 	}
154 
155 	std::cout << std::endl;
156 }
157