bool CUser::LoadModule(const CString& sModName, const CString& sArgs, const CString& sNotice, CString& sError) { bool bModRet = true; CString sModRet; CModInfo ModInfo; if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sModName, sModRet)) { sError = "Unable to find modinfo [" + sModName + "] [" + sModRet + "]"; return false; } CUtils::PrintAction(sNotice); if (!ModInfo.SupportsType(CModInfo::UserModule) && ModInfo.SupportsType(CModInfo::NetworkModule)) { CUtils::PrintMessage( "NOTICE: Module [" + sModName + "] is a network module, loading module for all networks in user."); // Do they have old NV? CFile fNVFile = CFile(GetUserPath() + "/moddata/" + sModName + "/.registry"); for (CIRCNetwork* pNetwork : m_vIRCNetworks) { // Check whether the network already has this module loaded (#954) if (pNetwork->GetModules().FindModule(sModName)) { continue; } if (fNVFile.Exists()) { CString sNetworkModPath = pNetwork->GetNetworkPath() + "/moddata/" + sModName; if (!CFile::Exists(sNetworkModPath)) { CDir::MakeDir(sNetworkModPath); } fNVFile.Copy(sNetworkModPath + "/.registry"); } bModRet = pNetwork->GetModules().LoadModule( sModName, sArgs, CModInfo::NetworkModule, this, pNetwork, sModRet); if (!bModRet) { break; } } } else { bModRet = GetModules().LoadModule(sModName, sArgs, CModInfo::UserModule, this, nullptr, sModRet); } if (!bModRet) { sError = sModRet; } return bModRet; }
void TryAddModInfo(const CString& sPath, const CString& sName, set<CModInfo>& ssMods, set<CString>& ssAlready, CModInfo::EModuleType eType) { if (ssAlready.count(sName)) { return; } PyObject* pyFunc = PyObject_GetAttrString(m_PyZNCModule, "get_mod_info_path"); if (!pyFunc) { CString sRetMsg = GetPyExceptionStr(); DEBUG("modpython tried to get info about [" << sPath << "] (1) but: " << sRetMsg); return; } CModInfo ModInfo; PyObject* pyRes = PyObject_CallFunction(pyFunc, const_cast<char*>("ssN"), sPath.c_str(), sName.c_str(), SWIG_NewInstanceObj(&ModInfo, SWIG_TypeQuery("CModInfo*"), 0)); if (!pyRes) { CString sRetMsg = GetPyExceptionStr(); DEBUG("modpython tried to get info about [" << sPath << "] (2) but: " << sRetMsg); Py_CLEAR(pyFunc); return; } Py_CLEAR(pyFunc); long int x = PyLong_AsLong(pyRes); if (PyErr_Occurred()) { CString sRetMsg = GetPyExceptionStr(); DEBUG("modpython tried to get info about [" << sPath << "] (3) but: " << sRetMsg); Py_CLEAR(pyRes); return; } Py_CLEAR(pyRes); if (x && ModInfo.SupportsType(eType)) { ssMods.insert(ModInfo); ssAlready.insert(sName); } }
void CModules::GetAvailableMods(set<CModInfo>& ssMods, CModInfo::EModuleType eType) { ssMods.clear(); unsigned int a = 0; CDir Dir; ModDirList dirs = GetModDirs(); while (!dirs.empty()) { Dir.FillByWildcard(dirs.front().first, "*.so"); dirs.pop(); for (a = 0; a < Dir.size(); a++) { CFile& File = *Dir[a]; CString sName = File.GetShortName(); CString sPath = File.GetLongName(); CModInfo ModInfo; sName.RightChomp(3); CString sIgnoreRetMsg; if (GetModPathInfo(ModInfo, sName, sPath, sIgnoreRetMsg)) { if (ModInfo.SupportsType(eType)) { ssMods.insert(ModInfo); } } } } GLOBALMODULECALL(OnGetAvailableMods(ssMods, eType), NOTHING); }
virtual void OnGetAvailableMods(set<CModInfo>& ssMods, CModInfo::EModuleType eType) override { unsigned int a = 0; CDir Dir; CModules::ModDirList dirs = CModules::GetModDirs(); while (!dirs.empty()) { Dir.FillByWildcard(dirs.front().first, "*.pm"); dirs.pop(); for (a = 0; a < Dir.size(); a++) { CFile& File = *Dir[a]; CString sName = File.GetShortName(); CString sPath = File.GetLongName(); CModInfo ModInfo; sName.RightChomp(3); PSTART; PUSH_STR(sPath); PUSH_STR(sName); PUSH_PTR(CModInfo*, &ModInfo); PCALL("ZNC::Core::ModInfoByPath"); if (SvTRUE(ERRSV)) { DEBUG(__PRETTY_FUNCTION__ << ": " << sPath << ": " << PString(ERRSV)); } else if (ModInfo.SupportsType(eType)) { ssMods.insert(ModInfo); } PEND; } } }
bool CUser::ParseConfig(CConfig* pConfig, CString& sError) { TOption<const CString&> StringOptions[] = { { "nick", &CUser::SetNick }, { "quitmsg", &CUser::SetQuitMsg }, { "altnick", &CUser::SetAltNick }, { "ident", &CUser::SetIdent }, { "realname", &CUser::SetRealName }, { "chanmodes", &CUser::SetDefaultChanModes }, { "bindhost", &CUser::SetBindHost }, { "vhost", &CUser::SetBindHost }, { "dccbindhost", &CUser::SetDCCBindHost }, { "dccvhost", &CUser::SetDCCBindHost }, { "timestampformat", &CUser::SetTimestampFormat }, { "skin", &CUser::SetSkinName }, { "language", &CUser::SetLanguage }, }; size_t numStringOptions = sizeof(StringOptions) / sizeof(StringOptions[0]); TOption<unsigned int> UIntOptions[] = { { "jointries", &CUser::SetJoinTries }, { "maxjoins", &CUser::SetMaxJoins }, }; size_t numUIntOptions = sizeof(UIntOptions) / sizeof(UIntOptions[0]); TOption<bool> BoolOptions[] = { { "keepbuffer", &CUser::SetKeepBuffer }, { "multiclients", &CUser::SetMultiClients }, { "denyloadmod", &CUser::SetDenyLoadMod }, { "admin", &CUser::SetAdmin }, { "denysetbindhost", &CUser::SetDenySetBindHost }, { "denysetvhost", &CUser::SetDenySetBindHost }, { "appendtimestamp", &CUser::SetTimestampAppend }, { "prependtimestamp", &CUser::SetTimestampPrepend }, { "ircconnectenabled", &CUser::SetIRCConnectEnabled }, }; size_t numBoolOptions = sizeof(BoolOptions) / sizeof(BoolOptions[0]); for (size_t i = 0; i < numStringOptions; i++) { CString sValue; if (pConfig->FindStringEntry(StringOptions[i].name, sValue)) (this->*StringOptions[i].pSetter)(sValue); } for (size_t i = 0; i < numUIntOptions; i++) { CString sValue; if (pConfig->FindStringEntry(UIntOptions[i].name, sValue)) (this->*UIntOptions[i].pSetter)(sValue.ToUInt()); } for (size_t i = 0; i < numBoolOptions; i++) { CString sValue; if (pConfig->FindStringEntry(BoolOptions[i].name, sValue)) (this->*BoolOptions[i].pSetter)(sValue.ToBool()); } VCString vsList; VCString::const_iterator vit; pConfig->FindStringVector("allow", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { AddAllowedHost(*vit); } pConfig->FindStringVector("ctcpreply", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { const CString& sValue = *vit; AddCTCPReply(sValue.Token(0), sValue.Token(1, true)); } CString sValue; CString sDCCLookupValue; pConfig->FindStringEntry("dcclookupmethod", sDCCLookupValue); if (pConfig->FindStringEntry("bouncedccs", sValue)) { if (sValue.ToBool()) { CUtils::PrintAction("Loading Module [bouncedcc]"); CString sModRet; bool bModRet = GetModules().LoadModule("bouncedcc", "", CModInfo::UserModule, this, NULL, sModRet); CUtils::PrintStatus(bModRet, sModRet); if (!bModRet) { sError = sModRet; return false; } if (sDCCLookupValue.Equals("Client")) { GetModules().FindModule("bouncedcc")->SetNV("UseClientIP", "1"); } } } if (pConfig->FindStringEntry("buffer", sValue)) SetBufferCount(sValue.ToUInt(), true); if (pConfig->FindStringEntry("awaysuffix", sValue)) { CUtils::PrintMessage("WARNING: AwaySuffix has been depricated, instead try -> LoadModule = awaynick %nick%_" + sValue); } if (pConfig->FindStringEntry("autocycle", sValue)) { if (sValue.Equals("true")) CUtils::PrintError("WARNING: AutoCycle has been removed, instead try -> LoadModule = autocycle"); } if (pConfig->FindStringEntry("keepnick", sValue)) { if (sValue.Equals("true")) CUtils::PrintError("WARNING: KeepNick has been deprecated, instead try -> LoadModule = keepnick"); } if (pConfig->FindStringEntry("statusprefix", sValue)) { if (!SetStatusPrefix(sValue)) { sError = "Invalid StatusPrefix [" + sValue + "] Must be 1-5 chars, no spaces."; CUtils::PrintError(sError); return false; } } if (pConfig->FindStringEntry("timezoneoffset", sValue)) { SetTimezoneOffset(sValue.ToDouble()); } if (pConfig->FindStringEntry("timestamp", sValue)) { if (!sValue.Trim_n().Equals("true")) { if (sValue.Trim_n().Equals("append")) { SetTimestampAppend(true); SetTimestampPrepend(false); } else if (sValue.Trim_n().Equals("prepend")) { SetTimestampAppend(false); SetTimestampPrepend(true); } else if (sValue.Trim_n().Equals("false")) { SetTimestampAppend(false); SetTimestampPrepend(false); } else { SetTimestampFormat(sValue); } } } pConfig->FindStringEntry("pass", sValue); // There are different formats for this available: // Pass = <plain text> // Pass = <md5 hash> - // Pass = plain#<plain text> // Pass = <hash name>#<hash> // Pass = <hash name>#<salted hash>#<salt># // 'Salted hash' means hash of 'password' + 'salt' // Possible hashes are md5 and sha256 if (sValue.Right(1) == "-") { sValue.RightChomp(); sValue.Trim(); SetPass(sValue, CUser::HASH_MD5); } else { CString sMethod = sValue.Token(0, false, "#"); CString sPass = sValue.Token(1, true, "#"); if (sMethod == "md5" || sMethod == "sha256") { CUser::eHashType type = CUser::HASH_MD5; if (sMethod == "sha256") type = CUser::HASH_SHA256; CString sSalt = sPass.Token(1, false, "#"); sPass = sPass.Token(0, false, "#"); SetPass(sPass, type, sSalt); } else if (sMethod == "plain") { SetPass(sPass, CUser::HASH_NONE); } else { SetPass(sValue, CUser::HASH_NONE); } } CConfig::SubConfig subConf; CConfig::SubConfig::const_iterator subIt; pConfig->FindSubConfig("pass", subConf); if (!sValue.empty() && !subConf.empty()) { sError = "Password defined more than once"; CUtils::PrintError(sError); return false; } subIt = subConf.begin(); if (subIt != subConf.end()) { CConfig* pSubConf = subIt->second.m_pSubConfig; CString sHash; CString sMethod; CString sSalt; CUser::eHashType method; pSubConf->FindStringEntry("hash", sHash); pSubConf->FindStringEntry("method", sMethod); pSubConf->FindStringEntry("salt", sSalt); if (sMethod.empty() || sMethod.Equals("plain")) method = CUser::HASH_NONE; else if (sMethod.Equals("md5")) method = CUser::HASH_MD5; else if (sMethod.Equals("sha256")) method = CUser::HASH_SHA256; else { sError = "Invalid hash method"; CUtils::PrintError(sError); return false; } SetPass(sHash, method, sSalt); if (!pSubConf->empty()) { sError = "Unhandled lines in config!"; CUtils::PrintError(sError); CZNC::DumpConfig(pSubConf); return false; } subIt++; } if (subIt != subConf.end()) { sError = "Password defined more than once"; CUtils::PrintError(sError); return false; } pConfig->FindSubConfig("network", subConf); for (subIt = subConf.begin(); subIt != subConf.end(); ++subIt) { const CString& sNetworkName = subIt->first; CIRCNetwork *pNetwork = FindNetwork(sNetworkName); if (!pNetwork) { pNetwork = new CIRCNetwork(this, sNetworkName); } if (!pNetwork->ParseConfig(subIt->second.m_pSubConfig, sError)) { return false; } } if (pConfig->FindStringVector("server", vsList, false) || pConfig->FindStringVector("chan", vsList, false) || pConfig->FindSubConfig("chan", subConf, false)) { CIRCNetwork *pNetwork = FindNetwork("user"); if (!pNetwork) { pNetwork = AddNetwork("user"); } if (pNetwork) { CUtils::PrintMessage("NOTICE: Found deprecated config, upgrading to a network"); if (!pNetwork->ParseConfig(pConfig, sError, true)) { return false; } } } pConfig->FindStringVector("loadmodule", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { sValue = *vit; CString sModName = sValue.Token(0); // XXX Legacy crap, added in ZNC 0.089 if (sModName == "discon_kick") { CUtils::PrintMessage("NOTICE: [discon_kick] was renamed, loading [disconkick] instead"); sModName = "disconkick"; } // XXX Legacy crap, added in ZNC 0.099 if (sModName == "fixfreenode") { CUtils::PrintMessage("NOTICE: [fixfreenode] doesn't do anything useful anymore, ignoring it"); continue; } CUtils::PrintAction("Loading Module [" + sModName + "]"); CString sModRet; CString sArgs = sValue.Token(1, true); bool bModRet; CModInfo ModInfo; if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sModName, sModRet)) { sError = "Unable to find modinfo [" + sModName + "] [" + sModRet + "]"; return false; } if (!ModInfo.SupportsType(CModInfo::UserModule) && ModInfo.SupportsType(CModInfo::NetworkModule)) { CUtils::PrintMessage("NOTICE: Module [" + sModName + "] is a network module, loading module for all networks in user."); // Do they have old NV? CFile fNVFile = CFile(GetUserPath() + "/moddata/" + sModName + "/.registry"); for (vector<CIRCNetwork*>::iterator it = m_vIRCNetworks.begin(); it != m_vIRCNetworks.end(); ++it) { if (fNVFile.Exists()) { CString sNetworkModPath = (*it)->GetNetworkPath() + "/moddata/" + sModName; if (!CFile::Exists(sNetworkModPath)) { CDir::MakeDir(sNetworkModPath); } fNVFile.Copy(sNetworkModPath + "/.registry"); } bModRet = (*it)->GetModules().LoadModule(sModName, sArgs, CModInfo::NetworkModule, this, *it, sModRet); if (!bModRet) { break; } } } else { bModRet = GetModules().LoadModule(sModName, sArgs, CModInfo::UserModule, this, NULL, sModRet); } CUtils::PrintStatus(bModRet, sModRet); if (!bModRet) { sError = sModRet; return false; } continue; } return true; }
bool CModules::LoadModule(const CString& sModule, const CString& sArgs, CModInfo::EModuleType eType, CUser* pUser, CIRCNetwork *pNetwork, CString& sRetMsg) { sRetMsg = ""; if (FindModule(sModule) != NULL) { sRetMsg = "Module [" + sModule + "] already loaded."; return false; } bool bSuccess; bool bHandled = false; _GLOBALMODULECALL(OnModuleLoading(sModule, sArgs, eType, bSuccess, sRetMsg), pUser, pNetwork, NULL, &bHandled); if (bHandled) return bSuccess; CString sModPath, sDataPath; bool bVersionMismatch; CModInfo Info; if (!FindModPath(sModule, sModPath, sDataPath)) { sRetMsg = "Unable to find module [" + sModule + "]"; return false; } ModHandle p = OpenModule(sModule, sModPath, bVersionMismatch, Info, sRetMsg); if (!p) return false; if (bVersionMismatch) { dlclose(p); sRetMsg = "Version mismatch, recompile this module."; return false; } if (!Info.SupportsType(eType)) { dlclose(p); sRetMsg = "Module [" + sModule + "] does not support module type [" + CModInfo::ModuleTypeToString(eType) + "]."; return false; } if (!pUser && eType == CModInfo::UserModule) { dlclose(p); sRetMsg = "Module [" + sModule + "] requires a user."; return false; } if (!pNetwork && eType == CModInfo::NetworkModule) { dlclose(p); sRetMsg = "Module [" + sModule + "] requires a network."; return false; } CModule* pModule = Info.GetLoader()(p, pUser, pNetwork, sModule, sDataPath); pModule->SetDescription(Info.GetDescription()); pModule->SetType(eType); pModule->SetArgs(sArgs); pModule->SetModPath(CDir::ChangeDir(CZNC::Get().GetCurPath(), sModPath)); push_back(pModule); bool bLoaded; try { bLoaded = pModule->OnLoad(sArgs, sRetMsg); } catch (CModule::EModException) { bLoaded = false; sRetMsg = "Caught an exception"; } if (!bLoaded) { UnloadModule(sModule, sModPath); if (!sRetMsg.empty()) sRetMsg = "Module [" + sModule + "] aborted: " + sRetMsg; else sRetMsg = "Module [" + sModule + "] aborted."; return false; } if (!sRetMsg.empty()) { sRetMsg += "[" + sRetMsg + "] "; } sRetMsg += "[" + sModPath + "]"; return true; }