Exemple #1
0
/** Handle /MODULES
 */
CmdResult CommandModules::Handle (const std::vector<std::string>& parameters, User *user)
{
	// Don't ask remote servers about their modules unless the local user asking is an oper
	// 2.0 asks anyway, so let's handle that the same way
	bool for_us = (parameters.empty() || parameters[0] == ServerInstance->Config->ServerName);
	if ((!for_us) || (!IS_LOCAL(user)))
	{
		if (!user->IsOper())
		{
			user->WriteNotice("*** You cannot check what modules other servers have loaded.");
			return CMD_FAILURE;
		}

		// From an oper and not for us, forward
		if (!for_us)
			return CMD_SUCCESS;
	}

	const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules();

  	for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
	{
		Module* m = i->second;
		Version V = m->GetVersion();

		if (user->HasPrivPermission("servers/auspex"))
		{
			std::string flags("SvcC");
			int pos = 0;
			for (int mult = 1; mult <= VF_OPTCOMMON; mult *= 2, ++pos)
				if (!(V.Flags & mult))
					flags[pos] = '-';

#ifdef PURE_STATIC
			user->SendText(":%s 702 %s :%p %s %s :%s", ServerInstance->Config->ServerName.c_str(),
				user->nick.c_str(), (void*)m, m->ModuleSourceFile.c_str(), flags.c_str(), V.description.c_str());
#else
			std::string srcrev = m->ModuleDLLManager->GetVersion();
			user->SendText(":%s 702 %s :%p %s %s :%s - %s", ServerInstance->Config->ServerName.c_str(),
				user->nick.c_str(), (void*)m, m->ModuleSourceFile.c_str(), flags.c_str(), V.description.c_str(), srcrev.c_str());
#endif
		}
		else
		{
			user->SendText(":%s 702 %s :%s %s", ServerInstance->Config->ServerName.c_str(),
				user->nick.c_str(), m->ModuleSourceFile.c_str(), V.description.c_str());
		}
	}
	user->SendText(":%s 703 %s :End of MODULES list", ServerInstance->Config->ServerName.c_str(), user->nick.c_str());

	return CMD_SUCCESS;
}
Exemple #2
0
/** Handle /MODULES
 */
CmdResult CommandModules::Handle(User* user, const Params& parameters)
{
	// Don't ask remote servers about their modules unless the local user asking is an oper
	// 2.0 asks anyway, so let's handle that the same way
	bool for_us = (parameters.empty() || irc::equals(parameters[0], ServerInstance->Config->ServerName));
	if ((!for_us) || (!IS_LOCAL(user)))
	{
		if (!user->IsOper())
		{
			user->WriteNotice("*** You cannot check what modules other servers have loaded.");
			return CMD_FAILURE;
		}

		// From an oper and not for us, forward
		if (!for_us)
			return CMD_SUCCESS;
	}

	const ModuleManager::ModuleMap& mods = ServerInstance->Modules.GetModules();

  	for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
	{
		Module* m = i->second;
		Version V = m->GetVersion();

		if (IS_LOCAL(user) && user->HasPrivPermission("servers/auspex"))
		{
			std::string flags("VCO");
			size_t pos = 0;
			for (int mult = 2; mult <= VF_OPTCOMMON; mult *= 2, ++pos)
				if (!(V.Flags & mult))
					flags[pos] = '-';

			std::string srcrev = m->ModuleDLLManager->GetVersion();
			user->WriteRemoteNumeric(RPL_MODLIST, m->ModuleSourceFile, srcrev.empty() ? "*" : srcrev, flags, V.description);
		}
		else
		{
			user->WriteRemoteNumeric(RPL_MODLIST, m->ModuleSourceFile, '*', '*', V.description);
		}
	}
	user->WriteRemoteNumeric(RPL_ENDOFMODLIST, "End of MODULES list");

	return CMD_SUCCESS;
}
Exemple #3
0
std::string TreeSocket::MyModules(int filter)
{
	std::vector<std::string> modlist = ServerInstance->Modules->GetAllModuleNames(filter);

	std::string capabilities;
	sort(modlist.begin(),modlist.end());
	for (std::vector<std::string>::const_iterator i = modlist.begin(); i != modlist.end(); ++i)
	{
		if (i != modlist.begin())
			capabilities.push_back(' ');
		capabilities.append(*i);
		Module* m = ServerInstance->Modules->Find(*i);
		Version v = m->GetVersion();
		if (!v.link_data.empty())
		{
			capabilities.push_back('=');
			capabilities.append(v.link_data);
		}
	}
	return capabilities;
}
Exemple #4
0
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const parameterlist& parameters, User* user)
{
	const std::string& command = thiscmd->name;
	RouteDescriptor routing = thiscmd->GetRouting(user, parameters);
	if (routing.type == ROUTE_TYPE_LOCALONLY)
		return;

	const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST));
	CmdBuilder params(user, encap ? "ENCAP" : command.c_str());

	if (routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.push('*');
		params.push_back(command);
	}
	else if (routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		TreeServer* sdest = FindServer(routing.serverdest);
		if (!sdest)
		{
			ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Trying to route ENCAP to nonexistant server %s",
				routing.serverdest.c_str());
			return;
		}
		params.push_back(sdest->GetID());
		params.push_back(command);
	}
	else
	{
		Module* srcmodule = thiscmd->creator;
		Version ver = srcmodule->GetVersion();

		if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator)
		{
			ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s",
				command.c_str(), srcmodule->ModuleSourceFile.c_str());
			return;
		}
	}

	std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd);

	params.push_back(output_text);

	if (routing.type == ROUTE_TYPE_MESSAGE)
	{
		char pfx = 0;
		std::string dest = routing.serverdest;
		if (ServerInstance->Modes->FindPrefix(dest[0]))
		{
			pfx = dest[0];
			dest = dest.substr(1);
		}
		if (dest[0] == '#')
		{
			Channel* c = ServerInstance->FindChan(dest);
			if (!c)
				return;
			// TODO OnBuildExemptList hook was here
			CUList exempts;
			SendChannelMessage(user->uuid, c, parameters[1], pfx, exempts, command.c_str(), origin ? origin->GetSocket() : NULL);
		}
		else if (dest[0] == '$')
		{
			params.Forward(origin);
		}
		else
		{
			// user target?
			User* d = ServerInstance->FindNick(dest);
			if (!d)
				return;
			TreeServer* tsd = BestRouteTo(d->server);
			if (tsd == origin)
				// huh? no routing stuff around in a circle, please.
				return;
			params.Unicast(d);
		}
	}
	else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.Forward(origin);
	}
	else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		if (origin && routing.serverdest == origin->GetName())
			return;
		params.Unicast(routing.serverdest);
	}
}
bool ModuleManager::Load(const std::string& modname, bool defer)
{
    /* Don't allow people to specify paths for modules, it doesn't work as expected */
    if (modname.find('/') != std::string::npos)
    {
        LastModuleError = "You can't load modules with a path: " + modname;
        return false;
    }

    const std::string filename = ExpandModName(modname);
    const std::string moduleFile = ServerInstance->Config->Paths.PrependModule(filename);

    if (!FileSystem::FileExists(moduleFile))
    {
        LastModuleError = "Module file could not be found: " + filename;
        ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
        return false;
    }

    if (Modules.find(filename) != Modules.end())
    {
        LastModuleError = "Module " + filename + " is already loaded, cannot load a module twice!";
        ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
        return false;
    }

    Module* newmod = NULL;
    DLLManager* newhandle = new DLLManager(moduleFile.c_str());
    ServiceList newservices;
    if (!defer)
        this->NewServices = &newservices;

    try
    {
        newmod = newhandle->CallInit();
        this->NewServices = NULL;

        if (newmod)
        {
            newmod->ModuleSourceFile = filename;
            newmod->ModuleDLLManager = newhandle;
            newmod->dying = false;
            Modules[filename] = newmod;
            std::string version = newhandle->GetVersion();
            if (defer)
            {
                ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)",
                                          filename.c_str(), version.c_str());
            }
            else
            {
                ConfigStatus confstatus;

                AttachAll(newmod);
                AddServices(newservices);
                newmod->init();
                newmod->ReadConfig(confstatus);

                Version v = newmod->GetVersion();
                ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)%s",
                                          filename.c_str(), version.c_str(), (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]"));
            }
        }
        else
        {
            LastModuleError = "Unable to load " + filename + ": " + newhandle->LastError();
            ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
            delete newhandle;
            return false;
        }
    }
    catch (CoreException& modexcept)
    {
        this->NewServices = NULL;

        // failure in module constructor
        if (newmod)
        {
            DoSafeUnload(newmod);
            ServerInstance->GlobalCulls.AddItem(newhandle);
        }
        else
            delete newhandle;
        LastModuleError = "Unable to load " + filename + ": " + modexcept.GetReason();
        ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
        return false;
    }

    if (defer)
        return true;

    FOREACH_MOD(OnLoadModule, (newmod));
    PrioritizeHooks();
    ServerInstance->ISupport.Build();
    return true;
}
Exemple #6
0
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, Command* thiscmd, const parameterlist& parameters, User* user)
{
	const std::string& command = thiscmd->name;
	RouteDescriptor routing = thiscmd->GetRouting(user, parameters);

	std::string sent_cmd = command;
	parameterlist params;

	if (routing.type == ROUTE_TYPE_LOCALONLY)
	{
		return;
	}
	else if (routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.push_back("*");
		params.push_back(command);
		sent_cmd = "ENCAP";
	}
	else if (routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		TreeServer* sdest = FindServer(routing.serverdest);
		if (!sdest)
		{
			ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Trying to route ENCAP to nonexistant server %s",
				routing.serverdest.c_str());
			return;
		}
		params.push_back(sdest->GetID());
		params.push_back(command);
		sent_cmd = "ENCAP";
	}
	else
	{
		Module* srcmodule = thiscmd->creator;
		Version ver = srcmodule->GetVersion();

		if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator)
		{
			ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s",
				command.c_str(), srcmodule->ModuleSourceFile.c_str());
			return;
		}
	}

	std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd);

	params.push_back(output_text);

	if (routing.type == ROUTE_TYPE_MESSAGE)
	{
		char pfx = 0;
		std::string dest = routing.serverdest;
		if (ServerInstance->Modes->FindPrefix(dest[0]))
		{
			pfx = dest[0];
			dest = dest.substr(1);
		}
		if (dest[0] == '#')
		{
			Channel* c = ServerInstance->FindChan(dest);
			if (!c)
				return;
			TreeServerList list;
			// TODO OnBuildExemptList hook was here
			GetListOfServersForChannel(c,list,pfx, CUList());
			std::string data = ":" + user->uuid + " " + sent_cmd;
			for (unsigned int x = 0; x < params.size(); x++)
				data += " " + params[x];
			for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
			{
				TreeSocket* Sock = (*i)->GetSocket();
				if (origin && origin->GetSocket() == Sock)
					continue;
				if (Sock)
					Sock->WriteLine(data);
			}
		}
		else if (dest[0] == '$')
		{
			if (origin)
				DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName());
			else
				DoOneToMany(user->uuid, sent_cmd, params);
		}
		else
		{
			// user target?
			User* d = ServerInstance->FindNick(dest);
			if (!d)
				return;
			TreeServer* tsd = BestRouteTo(d->server);
			if (tsd == origin)
				// huh? no routing stuff around in a circle, please.
				return;
			DoOneToOne(user->uuid, sent_cmd, params, d->server);
		}
	}
	else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		if (origin)
			DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName());
		else
			DoOneToMany(user->uuid, sent_cmd, params);
	}
	else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		if (origin && routing.serverdest == origin->GetName())
			return;
		DoOneToOne(user->uuid, sent_cmd, params, routing.serverdest);
	}
}
Exemple #7
0
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const CommandBase::Params& parameters, User* user)
{
	const std::string& command = thiscmd->name;
	RouteDescriptor routing = thiscmd->GetRouting(user, parameters);
	if (routing.type == ROUTE_TYPE_LOCALONLY)
		return;

	const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST));
	CmdBuilder params(user, encap ? "ENCAP" : command.c_str());
	params.push_tags(parameters.GetTags());
	TreeServer* sdest = NULL;

	if (routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.push('*');
		params.push_back(command);
	}
	else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		sdest = static_cast<TreeServer*>(routing.server);
		if (!sdest)
		{
			// Assume the command handler already validated routing.serverdest and have only returned success if the target is something that the
			// user executing the command is allowed to look up e.g. target is not an uuid if user is local.
			sdest = FindRouteTarget(routing.serverdest);
			if (!sdest)
			{
				ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Trying to route %s%s to nonexistent server %s", (encap ? "ENCAP " : ""), command.c_str(), routing.serverdest.c_str());
				return;
			}
		}

		if (encap)
		{
			params.push_back(sdest->GetID());
			params.push_back(command);
		}
	}
	else
	{
		Module* srcmodule = thiscmd->creator;
		Version ver = srcmodule->GetVersion();

		if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator)
		{
			ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s",
				command.c_str(), srcmodule->ModuleSourceFile.c_str());
			return;
		}
	}

	std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd);

	params.push_back(output_text);

	if (routing.type == ROUTE_TYPE_MESSAGE)
	{
		char pfx = 0;
		std::string dest = routing.serverdest;
		if (ServerInstance->Modes.FindPrefix(dest[0]))
		{
			pfx = dest[0];
			dest.erase(dest.begin());
		}
		if (dest[0] == '#')
		{
			Channel* c = ServerInstance->FindChan(dest);
			if (!c)
				return;
			// TODO OnBuildExemptList hook was here
			CUList exempts;
			std::string message;
			if (parameters.size() >= 2)
				message.assign(parameters[1]);
			SendChannelMessage(user->uuid, c, message, pfx, parameters.GetTags(), exempts, command.c_str(), origin ? origin->GetSocket() : NULL);
		}
		else if (dest[0] == '$')
		{
			params.Forward(origin);
		}
		else
		{
			// user target?
			User* d = ServerInstance->FindNick(dest);
			if (!d || IS_LOCAL(d))
				return;
			TreeServer* tsd = TreeServer::Get(d)->GetRoute();
			if (tsd == origin)
				// huh? no routing stuff around in a circle, please.
				return;
			params.Unicast(d);
		}
	}
	else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.Forward(origin);
	}
	else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		params.Unicast(sdest->ServerUser);
	}
}
bool ModuleManager::Load(const std::string& filename, bool defer)
{
	/* Don't allow people to specify paths for modules, it doesn't work as expected */
	if (filename.find('/') != std::string::npos)
		return false;

	char modfile[MAXBUF];
	snprintf(modfile,MAXBUF,"%s/%s",ServerInstance->Config->ModPath.c_str(),filename.c_str());

	if (!ServerConfig::FileExists(modfile))
	{
		LastModuleError = "Module file could not be found: " + filename;
		ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
		return false;
	}

	if (Modules.find(filename) != Modules.end())
	{
		LastModuleError = "Module " + filename + " is already loaded, cannot load a module twice!";
		ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
		return false;
	}

	Module* newmod = NULL;
	DLLManager* newhandle = new DLLManager(modfile);

	try
	{
		newmod = newhandle->CallInit();

		if (newmod)
		{
			newmod->ModuleSourceFile = filename;
			newmod->ModuleDLLManager = newhandle;
			newmod->dying = false;
			Modules[filename] = newmod;
			std::string version = newhandle->GetVersion();
			if (defer)
			{
				ServerInstance->Logs->Log("MODULE", LOG_DEFAULT,"New module introduced: %s (Module version %s)",
					filename.c_str(), version.c_str());
			}
			else
			{
				newmod->init();

				Version v = newmod->GetVersion();
				ServerInstance->Logs->Log("MODULE", LOG_DEFAULT,"New module introduced: %s (Module version %s)%s",
					filename.c_str(), version.c_str(), (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]"));
			}
		}
		else
		{
			LastModuleError = "Unable to load " + filename + ": " + newhandle->LastError();
			ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
			delete newhandle;
			return false;
		}
	}
	catch (CoreException& modexcept)
	{
		// failure in module constructor
		if (newmod)
		{
			DoSafeUnload(newmod);
			ServerInstance->GlobalCulls.AddItem(newhandle);
		}
		else
			delete newhandle;
		LastModuleError = "Unable to load " + filename + ": " + modexcept.GetReason();
		ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
		return false;
	}

	this->ModCount++;
	if (defer)
		return true;

	FOREACH_MOD(I_OnLoadModule,OnLoadModule(newmod));
	/* We give every module a chance to re-prioritize when we introduce a new one,
	 * not just the one thats loading, as the new module could affect the preference
	 * of others
	 */
	for(int tries = 0; tries < 20; tries++)
	{
		prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
		for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
			n->second->Prioritize();

		if (prioritizationState == PRIO_STATE_LAST)
			break;
		if (tries == 19)
			ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Hook priority dependency loop detected while loading " + filename);
	}

	ServerInstance->ISupport.Build();
	return true;
}
Exemple #9
0
ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
{
	if (modname.empty())
		return MOD_ERR_PARAMS;

	if (FindModule(modname))
		return MOD_ERR_EXISTS;

	Log(LOG_DEBUG) << "trying to load [" << modname <<  "]";

	/* Generate the filename for the temporary copy of the module */
	Anope::string pbuf = services_dir + "/modules/runtime/" + modname + ".so.XXXXXX";

	/* Don't skip return value checking! -GD */
	ModuleReturn ret = moduleCopyFile(modname, pbuf);
	if (ret != MOD_ERR_OK)
		return ret;

	dlerror();
	void *handle = dlopen(pbuf.c_str(), RTLD_LAZY);
	const char *err = dlerror();
	if (!handle && err && *err)
	{
		Log() << err;
		return MOD_ERR_NOLOAD;
	}

	dlerror();
	Module *(*func)(const Anope::string &, const Anope::string &) = function_cast<Module *(*)(const Anope::string &, const Anope::string &)>(dlsym(handle, "AnopeInit"));
	err = dlerror();
	if (!func && err && *err)
	{
		Log() << "No init function found, not an Anope module";
		dlclose(handle);
		return MOD_ERR_NOLOAD;
	}

	if (!func)
		throw CoreException("Couldn't find constructor, yet moderror wasn't set?");

	/* Create module. */
	Anope::string nick;
	if (u)
		nick = u->nick;

	Module *m;

	try
	{
		m = func(modname, nick);
	}
	catch (const ModuleException &ex)
	{
		Log() << "Error while loading " << modname << ": " << ex.GetReason();
		return MOD_ERR_EXCEPTION;
	}

	m->filename = pbuf;
	m->handle = handle;

	Version v = m->GetVersion();
	if (v.GetMajor() < Anope::VersionMajor() || (v.GetMajor() == Anope::VersionMajor() && v.GetMinor() < Anope::VersionMinor()))
	{
		Log() << "Module " << modname << " is compiled against an older version of Anope " << v.GetMajor() << "." << v.GetMinor() << ", this is " << Anope::VersionMajor() << "." << Anope::VersionMinor();
		DeleteModule(m);
		return MOD_ERR_VERSION;
	}
	else if (v.GetMajor() > Anope::VersionMajor() || (v.GetMajor() == Anope::VersionMajor() && v.GetMinor() > Anope::VersionMinor()))
	{
		Log() << "Module " << modname << " is compiled against a newer version of Anope " << v.GetMajor() << "." << v.GetMinor() << ", this is " << Anope::VersionMajor() << "." << Anope::VersionMinor();
		DeleteModule(m);
		return MOD_ERR_VERSION;
	}
	else if (v.GetBuild() < Anope::VersionBuild())
		Log() << "Module " << modname << " is compiled against an older revision of Anope " << v.GetBuild() << ", this is " << Anope::VersionBuild();
	else if (v.GetBuild() > Anope::VersionBuild())
		Log() << "Module " << modname << " is compiled against a newer revision of Anope " << v.GetBuild() << ", this is " << Anope::VersionBuild();
	else if (v.GetBuild() == Anope::VersionBuild())
		Log(LOG_DEBUG) << "Module " << modname << " compiled against current version of Anope " << v.GetBuild();

	if (m->type == PROTOCOL && ModuleManager::FindFirstOf(PROTOCOL) != m)
	{
		DeleteModule(m);
		Log() << "You cannot load two protocol modules";
		return MOD_ERR_UNKNOWN;
	}

	FOREACH_MOD(I_OnModuleLoad, OnModuleLoad(u, m));

	return MOD_ERR_OK;
}
Exemple #10
0
bool InspIRCd::LoadModule(const char* filename)
{
	/* Do we have a glob pattern in the filename?
	 * The user wants to load multiple modules which
	 * match the pattern.
	 */
	if (strchr(filename,'*') || (strchr(filename,'?')))
	{
		int n_match = 0;
		DIR* library = opendir(Config->ModPath);
		if (library)
		{
			/* Try and locate and load all modules matching the pattern */
			dirent* entry = NULL;
			while ((entry = readdir(library)))
			{
				if (this->MatchText(entry->d_name, filename))
				{
					if (!this->LoadModule(entry->d_name))
						n_match++;
				}
			}
			closedir(library);
		}
		/* Loadmodule will now return false if any one of the modules failed
		 * to load (but wont abort when it encounters a bad one) and when 1 or
		 * more modules were actually loaded.
		 */
		return (n_match > 0);
	}

	char modfile[MAXBUF];
	snprintf(modfile,MAXBUF,"%s/%s",Config->ModPath,filename);
	std::string filename_str = filename;

	if (!ServerConfig::DirValid(modfile))
	{
		this->Log(DEFAULT,"Module %s is not within the modules directory.",modfile);
		snprintf(MODERR,MAXBUF,"Module %s is not within the modules directory.",modfile);
		return false;
	}
	if (ServerConfig::FileExists(modfile))
	{

		for (unsigned int j = 0; j < Config->module_names.size(); j++)
		{
			if (Config->module_names[j] == filename_str)
			{
				this->Log(DEFAULT,"Module %s is already loaded, cannot load a module twice!",modfile);
				snprintf(MODERR,MAXBUF,"Module already loaded");
				return false;
			}
		}
		Module* m = NULL;
		ircd_module* a = NULL;
		try
		{
			a = new ircd_module(this, modfile);
			factory[this->ModCount+1] = a;
			if (factory[this->ModCount+1]->LastError())
			{
				this->Log(DEFAULT,"Unable to load %s: %s",modfile,factory[this->ModCount+1]->LastError());
				snprintf(MODERR,MAXBUF,"Loader/Linker error: %s",factory[this->ModCount+1]->LastError());
				return false;
			}
			if ((long)factory[this->ModCount+1]->factory != -1)
			{
				m = factory[this->ModCount+1]->factory->CreateModule(this);

				Version v = m->GetVersion();

				if (v.API != API_VERSION)
				{
					delete m;
					this->Log(DEFAULT,"Unable to load %s: Incorrect module API version: %d (our version: %d)",modfile,v.API,API_VERSION);
					snprintf(MODERR,MAXBUF,"Loader/Linker error: Incorrect module API version: %d (our version: %d)",v.API,API_VERSION);
					return false;
				}
				else
				{
					this->Log(DEFAULT,"New module introduced: %s (API version %d, Module version %d.%d.%d.%d)%s", filename, v.API, v.Major, v.Minor, v.Revision, v.Build, (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]"));
				}

				modules[this->ModCount+1] = m;
				/* save the module and the module's classfactory, if
				 * this isnt done, random crashes can occur :/ */
				Config->module_names.push_back(filename);

				char* x = &Config->implement_lists[this->ModCount+1][0];
				for(int t = 0; t < 255; t++)
					x[t] = 0;

				modules[this->ModCount+1]->Implements(x);

				for(int t = 0; t < 255; t++)
					Config->global_implementation[t] += Config->implement_lists[this->ModCount+1][t];
			}
			else
			{
				this->Log(DEFAULT,"Unable to load %s",modfile);
				snprintf(MODERR,MAXBUF,"Factory function failed: Probably missing init_module() entrypoint.");
				return false;
			}
		}
		catch (CoreException& modexcept)
		{
			this->Log(DEFAULT,"Unable to load %s: %s",modfile,modexcept.GetReason());
			snprintf(MODERR,MAXBUF,"Factory function of %s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
			return false;
		}
	}
	else
	{
		this->Log(DEFAULT,"InspIRCd: startup: Module Not Found %s",modfile);
		snprintf(MODERR,MAXBUF,"Module file could not be found");
		return false;
	}
	this->ModCount++;
	FOREACH_MOD_I(this,I_OnLoadModule,OnLoadModule(modules[this->ModCount],filename_str));
	// now work out which modules, if any, want to move to the back of the queue,
	// and if they do, move them there.
	std::vector<std::string> put_to_back;
	std::vector<std::string> put_to_front;
	std::map<std::string,std::string> put_before;
	std::map<std::string,std::string> put_after;
	for (unsigned int j = 0; j < Config->module_names.size(); j++)
	{
		if (modules[j]->Prioritize() == PRIORITY_LAST)
			put_to_back.push_back(Config->module_names[j]);
		else if (modules[j]->Prioritize() == PRIORITY_FIRST)
			put_to_front.push_back(Config->module_names[j]);
		else if ((modules[j]->Prioritize() & 0xFF) == PRIORITY_BEFORE)
			put_before[Config->module_names[j]] = Config->module_names[modules[j]->Prioritize() >> 8];
		else if ((modules[j]->Prioritize() & 0xFF) == PRIORITY_AFTER)
			put_after[Config->module_names[j]] = Config->module_names[modules[j]->Prioritize() >> 8];
	}
Exemple #11
0
ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
{
	if (modname.empty())
		return MOD_ERR_PARAMS;

	if (FindModule(modname))
		return MOD_ERR_EXISTS;

	Log(LOG_DEBUG) << "Trying to load module: " << modname;

#ifdef _WIN32
	/* Generate the filename for the temporary copy of the module */
	Anope::string pbuf = Anope::DataDir + "/runtime/" + modname + ".so.XXXXXX";

	/* Don't skip return value checking! -GD */
	ModuleReturn ret = moduleCopyFile(modname, pbuf);
	if (ret != MOD_ERR_OK)
	{
		if (ret == MOD_ERR_NOEXIST)
			Log(LOG_TERMINAL) << "Error while loading " << modname << " (file does not exist)";
		else if (ret == MOD_ERR_FILE_IO)
			Log(LOG_TERMINAL) << "Error while loading " << modname << " (file IO error, check file permissions and diskspace)";
		return ret;
	}
#else
	Anope::string pbuf = Anope::ModuleDir + "/modules/" + modname + ".so";
#endif

	dlerror();
	void *handle = dlopen(pbuf.c_str(), RTLD_NOW);
	const char *err = dlerror();
	if (!handle)
	{
		if (err && *err)
			Log() << err;
		return MOD_ERR_NOLOAD;
	}

	dlerror();
	Module *(*func)(const Anope::string &, const Anope::string &) = function_cast<Module *(*)(const Anope::string &, const Anope::string &)>(dlsym(handle, "AnopeInit"));
	err = dlerror();
	if (!func)
	{
		Log() << "No init function found, not an Anope module";
		if (err && *err)
			Log(LOG_DEBUG) << err;
		dlclose(handle);
		return MOD_ERR_NOLOAD;
	}
	
	/* Create module. */
	Anope::string nick;
	if (u)
		nick = u->nick;

	Module *m;

	ModuleReturn moderr = MOD_ERR_OK;
	try
	{
		m = func(modname, nick);
	}
	catch (const ModuleException &ex)
	{
		Log() << "Error while loading " << modname << ": " << ex.GetReason();
		moderr = MOD_ERR_EXCEPTION;
	}
	
	if (moderr != MOD_ERR_OK)
	{
		if (dlclose(handle))
			Log() << dlerror();
		return moderr;
	}

	m->filename = pbuf;
	m->handle = handle;

	ModuleVersion v = m->GetVersion();
	if (v.GetMajor() < Anope::VersionMajor() || (v.GetMajor() == Anope::VersionMajor() && v.GetMinor() < Anope::VersionMinor()))
	{
		Log() << "Module " << modname << " is compiled against an older version of Anope " << v.GetMajor() << "." << v.GetMinor() << ", this is " << Anope::VersionShort();
		DeleteModule(m);
		return MOD_ERR_VERSION;
	}
	else if (v.GetMajor() > Anope::VersionMajor() || (v.GetMajor() == Anope::VersionMajor() && v.GetMinor() > Anope::VersionMinor()))
	{
		Log() << "Module " << modname << " is compiled against a newer version of Anope " << v.GetMajor() << "." << v.GetMinor() << ", this is " << Anope::VersionShort();
		DeleteModule(m);
		return MOD_ERR_VERSION;
	}
	else if (v.GetPatch() < Anope::VersionPatch())
	{
		Log() << "Module " << modname << " is compiled against an older version of Anope, " << v.GetMajor() << "." << v.GetMinor() << "." << v.GetPatch() << ", this is " << Anope::VersionShort();
		DeleteModule(m);
		return MOD_ERR_VERSION;
	}
	else if (v.GetPatch() > Anope::VersionPatch())
	{
		Log() << "Module " << modname << " is compiled against a newer version of Anope, " << v.GetMajor() << "." << v.GetMinor() << "." << v.GetPatch() << ", this is " << Anope::VersionShort();
		DeleteModule(m);
		return MOD_ERR_VERSION;
	}
	else
		Log(LOG_DEBUG_2) << "Module " << modname << " is compiled against current version of Anope " << Anope::VersionShort();

	/* Initialize config */
	try
	{
		m->OnReload(Config);
	}
	catch (const ModuleException &ex)
	{
		Log() << "Module " << modname << " couldn't load:" << ex.GetReason();
		moderr = MOD_ERR_EXCEPTION;
	}
	catch (const ConfigException &ex)
	{
		Log() << "Module " << modname << " couldn't load due to configuration problems: " << ex.GetReason();
		moderr = MOD_ERR_EXCEPTION;
	}
	catch (const NotImplementedException &ex)
	{
	}
	
	if (moderr != MOD_ERR_OK)
	{
		DeleteModule(m);
		return moderr;
	}

	Log(LOG_DEBUG) << "Module " << modname << " loaded.";

	/* Attach module to all events */
	for (unsigned i = 0; i < I_SIZE; ++i)
		EventHandlers[i].push_back(m);

	FOREACH_MOD(OnModuleLoad, (u, m));

	return MOD_ERR_OK;
}