X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fconfigreader.cpp;h=3be7d59452ebafb1f2f5b1295d7dd28d93e98f19;hb=0d2b6637ca369166629576f160ef1fd376078e5a;hp=f8f17038b0d0d1cb5bdaf946baddfa2b943a4b1e;hpb=61185fc62b7d3d05e33a116fca26aa9dc72ab691;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/configreader.cpp b/src/configreader.cpp index f8f17038b..3be7d5945 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -11,7 +11,7 @@ * --------------------------------------------------- */ -/* $Core: libIRCDconfigreader */ +/* $Core */ /* $CopyInstall: conf/inspircd.quotes.example $(CONPATH) */ /* $CopyInstall: conf/inspircd.rules.example $(CONPATH) */ /* $CopyInstall: conf/inspircd.motd.example $(CONPATH) */ @@ -19,7 +19,10 @@ /* $CopyInstall: conf/inspircd.helpop.example $(CONPATH) */ /* $CopyInstall: conf/inspircd.censor.example $(CONPATH) */ /* $CopyInstall: conf/inspircd.filter.example $(CONPATH) */ -/* $CopyInstall: docs/inspircd.conf.example $(CONPATH) */ +/* $CopyInstall: conf/inspircd.conf.example $(CONPATH) */ +/* $CopyInstall: conf/modules.conf.example $(CONPATH) */ +/* $CopyInstall: conf/opers.conf.example $(CONPATH) */ +/* $CopyInstall: conf/links.conf.example $(CONPATH) */ #include "inspircd.h" #include @@ -43,7 +46,7 @@ ServerConfig::ServerConfig(InspIRCd* Instance) : ServerInstance(Instance) WhoWasGroupSize = WhoWasMaxGroups = WhoWasMaxKeep = 0; log_file = NULL; NoUserDns = forcedebug = OperSpyWhois = nofork = HideBans = HideSplits = UndernetMsgPrefix = false; - CycleHosts = writelog = AllowHalfop = true; + CycleHosts = writelog = AllowHalfop = InvBypassModes = true; dns_timeout = DieDelay = 5; MaxTargets = 20; NetBufferSize = 10240; @@ -53,6 +56,8 @@ ServerConfig::ServerConfig(InspIRCd* Instance) : ServerInstance(Instance) debugging = 0; MaxChans = 20; OperMaxChans = 30; + c_ipv4_range = 32; + c_ipv6_range = 128; maxbans.clear(); DNSServerValidator = &ValidateDnsServer; } @@ -62,38 +67,6 @@ void ServerConfig::ClearStack() include_stack.clear(); } -Module* ServerConfig::GetIOHook(BufferedSocket* is) -{ - std::map::iterator x = SocketIOHookModule.find(is); - return (x != SocketIOHookModule.end() ? x->second : NULL); -} - -bool ServerConfig::AddIOHook(Module* iomod, BufferedSocket* is) -{ - if (!GetIOHook(is)) - { - SocketIOHookModule[is] = iomod; - is->IsIOHooked = true; - return true; - } - else - { - throw ModuleException("BufferedSocket derived class already hooked by another module"); - return false; - } -} - -bool ServerConfig::DelIOHook(BufferedSocket* is) -{ - std::map::iterator x = SocketIOHookModule.find(is); - if (x != SocketIOHookModule.end()) - { - SocketIOHookModule.erase(x); - return true; - } - return false; -} - void ServerConfig::Update005() { std::stringstream out(data005); @@ -125,7 +98,7 @@ void ServerConfig::Update005() void ServerConfig::Send005(User* user) { for (std::vector::iterator line = ServerInstance->Config->isupport.begin(); line != ServerInstance->Config->isupport.end(); line++) - user->WriteNumeric(005, "%s %s", user->nick.c_str(), line->c_str()); + user->WriteNumeric(RPL_ISUPPORT, "%s %s", user->nick.c_str(), line->c_str()); } bool ServerConfig::CheckOnce(const char* tag, ConfigDataHash &newconf) @@ -133,15 +106,9 @@ bool ServerConfig::CheckOnce(const char* tag, ConfigDataHash &newconf) int count = ConfValueEnum(newconf, tag); if (count > 1) - { throw CoreException("You have more than one <"+std::string(tag)+"> tag, this is not permitted."); - return false; - } if (count < 1) - { throw CoreException("You have not defined a <"+std::string(tag)+"> tag, this is required."); - return false; - } return true; } @@ -296,6 +263,28 @@ bool InitializeDisabledCommands(const char* data, InspIRCd* ServerInstance) return true; } +bool ValidateDisabledUModes(ServerConfig* conf, const char*, const char*, ValueItem &data) +{ + memset(conf->DisabledUModes, 0, sizeof(conf->DisabledUModes)); + for (const unsigned char* p = (const unsigned char*)data.GetString(); *p; ++p) + { + if (*p < 'A' || *p > ('A' + 64)) throw CoreException(std::string("Invalid usermode ")+(char)*p+" was found."); + conf->DisabledUModes[*p - 'A'] = 1; + } + return true; +} + +bool ValidateDisabledCModes(ServerConfig* conf, const char*, const char*, ValueItem &data) +{ + memset(conf->DisabledCModes, 0, sizeof(conf->DisabledCModes)); + for (const unsigned char* p = (const unsigned char*)data.GetString(); *p; ++p) + { + if (*p < 'A' || *p > ('A' + 64)) throw CoreException(std::string("Invalid chanmode ")+(char)*p+" was found."); + conf->DisabledCModes[*p - 'A'] = 1; + } + return true; +} + bool ValidateDnsServer(ServerConfig* conf, const char*, const char*, ValueItem &data) { if (!*(data.GetString())) @@ -350,7 +339,8 @@ bool ValidateServerName(ServerConfig* conf, const char*, const char*, ValueItem bool ValidateNetBufferSize(ServerConfig* conf, const char*, const char*, ValueItem &data) { - if ((!data.GetInteger()) || (data.GetInteger() > 65535) || (data.GetInteger() < 1024)) + // 65534 not 65535 because of null terminator + if ((!data.GetInteger()) || (data.GetInteger() > 65534) || (data.GetInteger() < 1024)) { conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"No NetBufferSize specified or size out of range, setting to default of 10240."); data.Set(10240); @@ -374,10 +364,10 @@ bool ValidateMotd(ServerConfig* conf, const char*, const char*, ValueItem &data) return true; } -bool ValidateNotEmpty(ServerConfig*, const char* tag, const char*, ValueItem &data) +bool ValidateNotEmpty(ServerConfig*, const char* tag, const char* val, ValueItem &data) { if (!*data.GetString()) - throw CoreException(std::string("The value for ")+tag+" cannot be empty!"); + throw CoreException(std::string("The value for <")+tag+":"+val+"> cannot be empty!"); return true; } @@ -389,7 +379,7 @@ bool ValidateRules(ServerConfig* conf, const char*, const char*, ValueItem &data bool ValidateModeLists(ServerConfig* conf, const char*, const char*, ValueItem &data) { - memset(conf->HideModeLists, 0, 256); + memset(conf->HideModeLists, 0, sizeof(conf->HideModeLists)); for (const unsigned char* x = (const unsigned char*)data.GetString(); *x; ++x) conf->HideModeLists[*x] = true; return true; @@ -397,7 +387,7 @@ bool ValidateModeLists(ServerConfig* conf, const char*, const char*, ValueItem & bool ValidateExemptChanOps(ServerConfig* conf, const char*, const char*, ValueItem &data) { - memset(conf->ExemptChanOps, 0, 256); + memset(conf->ExemptChanOps, 0, sizeof(conf->ExemptChanOps)); for (const unsigned char* x = (const unsigned char*)data.GetString(); *x; ++x) conf->ExemptChanOps[*x] = true; return true; @@ -465,13 +455,18 @@ bool ValidateWhoWas(ServerConfig* conf, const char*, const char*, ValueItem &dat */ bool InitConnect(ServerConfig* conf, const char*) { - conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Reading connect classes..."); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Reading connect classes... class list is:"); for (ClassVector::iterator i = conf->Classes.begin(); i != conf->Classes.end() ; ) { ConnectClass* c = *i; - /* only delete a class with refcount 0 */ + /* + * only delete a class with refcount 0. + * this is needed to avoid trampling on a wild pointer (User::MyClass)! + * it's also the most simple way to do it, given that we're looking at threads.. + * -- w00t + */ if (c->RefCount == 0) { conf->GetInstance()->Logs->Log("CONFIG",DEFAULT, "Removing connect class, refcount is 0!"); @@ -517,29 +512,10 @@ bool DoConnect(ServerConfig* conf, const char*, char**, ValueList &values, int*) unsigned long limit = values[15].GetInteger(); const char* hashtype = values[16].GetString(); - /* - * duplicates check: Now we don't delete all connect classes on rehash, we need to ensure we don't add dupes. - * easier said than done, but for now we'll just disallow anything with a duplicate host or name. -- w00t - */ - for (ClassVector::iterator item = conf->Classes.begin(); item != conf->Classes.end(); ++item) - { - ConnectClass* cc = *item; - if ( - ((*name && (cc->GetName() == name)) || // if the name is the same - (*allow && (cc->GetHost() == allow)) || // or the allow is the same - (*deny && (cc->GetHost() == deny))) && // or the deny is the same - (!port || port && (cc->GetPort() == port)) // and there is no port, or there is a port and the port is the same - ) - { - /* reenable class so users can be shoved into it :P */ - cc->SetDisabled(false); - conf->GetInstance()->Logs->Log("CONFIG",DEFAULT, "Not adding class, it already exists!"); - return true; - } - } - conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Adding a connect class!"); + ConnectClass *cc = NULL; + if (*parent) { /* Find 'parent' and inherit a new class from it, @@ -548,13 +524,13 @@ bool DoConnect(ServerConfig* conf, const char*, char**, ValueList &values, int*) ClassVector::iterator item = conf->Classes.begin(); for (; item != conf->Classes.end(); ++item) { - ConnectClass* cc = *item; + cc = *item; conf->GetInstance()->Logs->Log("CONFIG",DEBUG,"Class: %s", cc->GetName().c_str()); if (cc->GetName() == parent) { - ConnectClass* newclass = new ConnectClass(name, cc); - newclass->Update(timeout, flood, *allow ? allow : deny, pingfreq, password, threshold, sendq, recvq, localmax, globalmax, maxchans, port, limit); - conf->Classes.push_back(newclass); + cc = new ConnectClass(name, cc); + cc->Update(timeout, flood, *allow ? allow : deny, pingfreq, password, threshold, sendq, recvq, localmax, globalmax, maxchans, port, limit); + conf->Classes.push_back(cc); break; } } @@ -568,13 +544,13 @@ bool DoConnect(ServerConfig* conf, const char*, char**, ValueList &values, int*) /* Find existing class by mask, the mask should be unique */ for (ClassVector::iterator item = conf->Classes.begin(); item != conf->Classes.end(); ++item) { - if ((*item)->GetHost() == allow) + if ((*item)->GetHost() == allow && !(*item)->GetDisabled()) { (*item)->Update(timeout, flood, allow, pingfreq, password, threshold, sendq, recvq, localmax, globalmax, maxchans, port, limit); return true; } } - ConnectClass* cc = new ConnectClass(name, timeout, flood, allow, pingfreq, password, hashtype, threshold, sendq, recvq, localmax, globalmax, maxchans); + cc = new ConnectClass(name, timeout, flood, allow, pingfreq, password, hashtype, threshold, sendq, recvq, localmax, globalmax, maxchans); cc->limit = limit; cc->SetPort(port); conf->Classes.push_back(cc); @@ -584,14 +560,14 @@ bool DoConnect(ServerConfig* conf, const char*, char**, ValueList &values, int*) /* Find existing class by mask, the mask should be unique */ for (ClassVector::iterator item = conf->Classes.begin(); item != conf->Classes.end(); ++item) { - if ((*item)->GetHost() == deny) + if ((*item)->GetHost() == deny && !(*item)->GetDisabled()) { (*item)->Update(name, deny); (*item)->SetPort(port); return true; } } - ConnectClass* cc = new ConnectClass(name, deny); + cc = new ConnectClass(name, deny); cc->SetPort(port); conf->Classes.push_back(cc); } @@ -713,7 +689,7 @@ bool DoneMaxBans(ServerConfig*, const char*) return true; } -void ServerConfig::ReportConfigError(const std::string &errormessage, bool bail, User* user) +void ServerConfig::ReportConfigError(const std::string &errormessage, bool bail, const std::string &useruid) { ServerInstance->Logs->Log("CONFIG",DEFAULT, "There were errors in your configuration file: %s", errormessage.c_str()); if (bail) @@ -729,14 +705,18 @@ void ServerConfig::ReportConfigError(const std::string &errormessage, bool bail, unsigned int prefixlen; start = 0; /* ":ServerInstance->Config->ServerName NOTICE user->nick :" */ - if (user) + if (!useruid.empty()) { - prefixlen = strlen(this->ServerName) + user->nick.length() + 11; - user->WriteServ("NOTICE %s :There were errors in the configuration file:",user->nick.c_str()); - while (start < errors.length()) + User* user = ServerInstance->FindNick(useruid); + if (user) { - user->WriteServ("NOTICE %s :%s",user->nick.c_str(), errors.substr(start, 510 - prefixlen).c_str()); - start += 510 - prefixlen; + prefixlen = strlen(this->ServerName) + user->nick.length() + 11; + user->WriteServ("NOTICE %s :There were errors in the configuration file:",user->nick.c_str()); + while (start < errors.length()) + { + user->WriteServ("NOTICE %s :%s",user->nick.c_str(), errors.substr(start, 510 - prefixlen).c_str()); + start += 510 - prefixlen; + } } } else @@ -752,7 +732,7 @@ void ServerConfig::ReportConfigError(const std::string &errormessage, bool bail, } } -void ServerConfig::Read(bool bail, User* user) +void ServerConfig::Read(bool bail, const std::string &useruid) { int rem = 0, add = 0; /* Number of modules added, number of modules removed */ @@ -760,7 +740,10 @@ void ServerConfig::Read(bool bail, User* user) static char hidemodes[MAXBUF]; /* Modes to not allow listing from users below halfop */ static char exemptchanops[MAXBUF]; /* Exempt channel ops from these modes */ static char announceinvites[MAXBUF]; /* options:announceinvites setting */ - errstr.clear(); + static char disabledumodes[MAXBUF]; /* Disabled usermodes */ + static char disabledcmodes[MAXBUF]; /* Disabled chanmodes */ + /* std::ostringstream::clear() does not clear the string itself, only the error flags. */ + this->errstr = new std::ostringstream(std::stringstream::in | std::stringstream::out); include_stack.clear(); @@ -820,6 +803,12 @@ void ServerConfig::Read(bool bail, User* user) {"dns", "timeout", "5", new ValueContainerInt (&this->dns_timeout), DT_INTEGER, NoValidation}, {"options", "moduledir", MOD_PATH, new ValueContainerChar (this->ModPath), DT_CHARPTR, NoValidation}, {"disabled", "commands", "", new ValueContainerChar (this->DisabledCommands), DT_CHARPTR, NoValidation}, + {"disabled", "usermodes", "", new ValueContainerChar (disabledumodes), DT_CHARPTR, ValidateDisabledUModes}, + {"disabled", "chanmodes", "", new ValueContainerChar (disabledcmodes), DT_CHARPTR, ValidateDisabledCModes}, + {"disabled", "fakenonexistant", "0", new ValueContainerBool (&this->DisabledDontExist), DT_BOOLEAN, NoValidation}, + + {"security", "runasuser", "", new ValueContainerChar(this->SetUser), DT_CHARPTR, NoValidation}, + {"security", "runasgroup", "", new ValueContainerChar(this->SetGroup), DT_CHARPTR, NoValidation}, {"security", "userstats", "", new ValueContainerChar (this->UserStats), DT_CHARPTR, NoValidation}, {"security", "customversion","", new ValueContainerChar (this->CustomVersion), DT_CHARPTR, NoValidation}, {"security", "hidesplits", "0", new ValueContainerBool (&this->HideSplits), DT_BOOLEAN, NoValidation}, @@ -827,6 +816,7 @@ void ServerConfig::Read(bool bail, User* user) {"security", "hidewhois", "", new ValueContainerChar (this->HideWhoisServer), DT_NOSPACES, NoValidation}, {"security", "hidekills", "", new ValueContainerChar (this->HideKillsServer), DT_NOSPACES, NoValidation}, {"security", "operspywhois", "0", new ValueContainerBool (&this->OperSpyWhois), DT_BOOLEAN, NoValidation}, + {"security", "restrictbannedusers", "1", new ValueContainerBool (&this->RestrictBannedUsers), DT_BOOLEAN, NoValidation}, {"performance", "nouserdns", "0", new ValueContainerBool (&this->NoUserDns), DT_BOOLEAN, NoValidation}, {"options", "syntaxhints", "0", new ValueContainerBool (&this->SyntaxHints), DT_BOOLEAN, NoValidation}, {"options", "cyclehosts", "0", new ValueContainerBool (&this->CycleHosts), DT_BOOLEAN, NoValidation}, @@ -844,6 +834,8 @@ void ServerConfig::Read(bool bail, User* user) {"die", "value", "", new ValueContainerChar (this->DieValue), DT_CHARPTR, NoValidation}, {"channels", "users", "20", new ValueContainerUInt (&this->MaxChans), DT_INTEGER, NoValidation}, {"channels", "opers", "60", new ValueContainerUInt (&this->OperMaxChans), DT_INTEGER, NoValidation}, + {"cidr", "ipv4clone", "32", new ValueContainerInt (&this->c_ipv4_range), DT_INTEGER, NoValidation}, + {"cidr", "ipv6clone", "128", new ValueContainerInt (&this->c_ipv6_range), DT_INTEGER, NoValidation}, {"limits", "maxnick", "32", new ValueContainerST (&this->Limits.NickMax), DT_INTEGER, NoValidation}, {"limits", "maxchan", "64", new ValueContainerST (&this->Limits.ChanMax), DT_INTEGER, NoValidation}, {"limits", "maxmodes", "20", new ValueContainerST (&this->Limits.MaxModes), DT_INTEGER, NoValidation}, @@ -853,6 +845,7 @@ void ServerConfig::Read(bool bail, User* user) {"limits", "maxkick", "255", new ValueContainerST (&this->Limits.MaxKick), DT_INTEGER, NoValidation}, {"limits", "maxgecos", "128", new ValueContainerST (&this->Limits.MaxGecos), DT_INTEGER, NoValidation}, {"limits", "maxaway", "200", new ValueContainerST (&this->Limits.MaxAway), DT_INTEGER, NoValidation}, + {"options", "invitebypassmodes", "1", new ValueContainerBool (&this->InvBypassModes), DT_BOOLEAN, NoValidation}, {NULL, NULL, NULL, NULL, DT_NOTHING, NoValidation} }; @@ -927,9 +920,9 @@ void ServerConfig::Read(bool bail, User* user) InitTypes, DoType, DoneClassesAndTypes}, {"class", - {"name", "commands", "usermodes", "chanmodes", NULL}, - {"", "", "", "", NULL}, - {DT_NOSPACES, DT_CHARPTR, DT_CHARPTR, DT_CHARPTR}, + {"name", "commands", "usermodes", "chanmodes", "privs", NULL}, + {"", "", "", "", "", NULL}, + {DT_NOSPACES, DT_CHARPTR, DT_CHARPTR, DT_CHARPTR, DT_CHARPTR}, InitClasses, DoClass, DoneClassesAndTypes}, {NULL, @@ -944,11 +937,14 @@ void ServerConfig::Read(bool bail, User* user) /* Make a copy here so if it fails then we can carry on running with an unaffected config */ newconfig.clear(); - if (!this->DoInclude(newconfig, ServerInstance->ConfigFileName, errstr)) + if (!this->DoInclude(newconfig, ServerInstance->ConfigFileName, *errstr)) { - ReportConfigError(errstr.str(), bail, user); + ReportConfigError(errstr->str(), bail, useruid); + delete errstr; return; } + + delete errstr; /* The stuff in here may throw CoreException, be sure we're in a position to catch it. */ try @@ -965,8 +961,6 @@ void ServerConfig::Read(bool bail, User* user) *item = 0; if (ConfValue(newconfig, ChangedConfig[Index].tag, ChangedConfig[Index].value, "", 0, item, MAXBUF, true) || *item) throw CoreException(std::string("Your configuration contains a deprecated value: <") + ChangedConfig[Index].tag + ":" + ChangedConfig[Index].value + "> - " + ChangedConfig[Index].reason); - else - ServerInstance->Logs->Log("CONFIG",DEBUG,"Deprecated item <%s:%s> does not exist, good.", ChangedConfig[Index].tag, ChangedConfig[Index].value); } /* Read the values of all the tags which occur once or not at all, and call their callbacks. @@ -984,7 +978,10 @@ void ServerConfig::Read(bool bail, User* user) /* Silently ignore boot only values */ if (bootonly && !bail) + { + delete Values[Index].val; continue; + } ConfValue(newconfig, Values[Index].tag, Values[Index].value, Values[Index].default_value, 0, item, MAXBUF, allow_newlines); ValueItem vi(item); @@ -992,7 +989,7 @@ void ServerConfig::Read(bool bail, User* user) if (!Values[Index].validation_function(this, Values[Index].tag, Values[Index].value, vi)) throw CoreException("One or more values in your configuration file failed to validate. Please see your ircd.log for more information."); - ServerInstance->Threads->Mutex(true); + ServerInstance->Threads->Lock(); switch (dt) { case DT_NOSPACES: @@ -1021,7 +1018,7 @@ void ServerConfig::Read(bool bail, User* user) ValueContainerChar* vcc = (ValueContainerChar*)Values[Index].val; if (*(vi.GetString()) && !ServerInstance->IsChannel(vi.GetString(), MAXBUF)) { - ServerInstance->Threads->Mutex(false); + ServerInstance->Threads->Unlock(); throw CoreException("The value of <"+std::string(Values[Index].tag)+":"+Values[Index].value+"> is not a valid channel name"); } vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); @@ -1054,7 +1051,7 @@ void ServerConfig::Read(bool bail, User* user) } /* We're done with this now */ delete Values[Index].val; - ServerInstance->Threads->Mutex(false); + ServerInstance->Threads->Unlock(); } /* Read the multiple-tag items (class tags, connect tags, etc) @@ -1063,9 +1060,9 @@ void ServerConfig::Read(bool bail, User* user) */ for (int Index = 0; MultiValues[Index].tag; ++Index) { - ServerInstance->Threads->Mutex(true); + ServerInstance->Threads->Lock(); MultiValues[Index].init_function(this, MultiValues[Index].tag); - ServerInstance->Threads->Mutex(false); + ServerInstance->Threads->Unlock(); int number_of_tags = ConfValueEnum(newconfig, MultiValues[Index].tag); @@ -1080,7 +1077,7 @@ void ServerConfig::Read(bool bail, User* user) dt &= ~DT_ALLOW_NEWLINE; dt &= ~DT_ALLOW_WILD; - ServerInstance->Threads->Mutex(true); + ServerInstance->Threads->Lock(); /* We catch and rethrow any exception here just so we can free our mutex */ try @@ -1159,10 +1156,10 @@ void ServerConfig::Read(bool bail, User* user) } catch (CoreException &e) { - ServerInstance->Threads->Mutex(false); + ServerInstance->Threads->Unlock(); throw e; } - ServerInstance->Threads->Mutex(false); + ServerInstance->Threads->Unlock(); } MultiValues[Index].validation_function(this, MultiValues[Index].tag, (char**)MultiValues[Index].items, vl, MultiValues[Index].datatype); } @@ -1178,11 +1175,11 @@ void ServerConfig::Read(bool bail, User* user) catch (CoreException &ce) { - ReportConfigError(ce.GetReason(), bail, user); + ReportConfigError(ce.GetReason(), bail, useruid); return; } - ServerInstance->Threads->Mutex(true); + ServerInstance->Threads->Lock(); for (int i = 0; i < ConfValueEnum(newconfig, "type"); ++i) { char item[MAXBUF], classn[MAXBUF], classes[MAXBUF]; @@ -1205,8 +1202,12 @@ void ServerConfig::Read(bool bail, User* user) } if (!foundclass) { - if (user) - user->WriteServ("NOTICE %s :*** Warning: Oper type '%s' has a missing class named '%s', this does nothing!", user->nick.c_str(), item, classname.c_str()); + if (!useruid.empty()) + { + User* user = ServerInstance->FindNick(useruid); + if (user) + user->WriteServ("NOTICE %s :*** Warning: Oper type '%s' has a missing class named '%s', this does nothing!", user->nick.c_str(), item, classname.c_str()); + } else { if (bail) @@ -1221,7 +1222,7 @@ void ServerConfig::Read(bool bail, User* user) /* If we succeeded, set the ircd config to the new one */ this->config_data = newconfig; - ServerInstance->Threads->Mutex(false); + ServerInstance->Threads->Unlock(); // write once here, to try it out and make sure its ok ServerInstance->WritePID(this->PID); @@ -1240,20 +1241,24 @@ void ServerConfig::Read(bool bail, User* user) FailedPortList pl; ServerInstance->BindPorts(false, found_ports, pl); - if (pl.size() && user) + if (pl.size() && !useruid.empty()) { - ServerInstance->Threads->Mutex(true); - user->WriteServ("NOTICE %s :*** Not all your client ports could be bound.", user->nick.c_str()); - user->WriteServ("NOTICE %s :*** The following port(s) failed to bind:", user->nick.c_str()); - int j = 1; - for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++) + ServerInstance->Threads->Lock(); + User* user = ServerInstance->FindNick(useruid); + if (user) { - user->WriteServ("NOTICE %s :*** %d. IP: %s Port: %lu", user->nick.c_str(), j, i->first.empty() ? "" : i->first.c_str(), (unsigned long)i->second); + user->WriteServ("NOTICE %s :*** Not all your client ports could be bound.", user->nick.c_str()); + user->WriteServ("NOTICE %s :*** The following port(s) failed to bind:", user->nick.c_str()); + int j = 1; + for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++) + { + user->WriteServ("NOTICE %s :*** %d. Address: %s Reason: %s", user->nick.c_str(), j, i->first.empty() ? "" : i->first.c_str(), i->second.c_str()); + } } - ServerInstance->Threads->Mutex(false); + ServerInstance->Threads->Unlock(); } - ServerInstance->Threads->Mutex(true); + ServerInstance->Threads->Lock(); if (!removed_modules.empty()) { for (std::vector::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++) @@ -1262,15 +1267,27 @@ void ServerConfig::Read(bool bail, User* user) { ServerInstance->SNO->WriteToSnoMask('A', "*** REHASH UNLOADED MODULE: %s",removing->c_str()); - if (user) - user->WriteNumeric(973, "%s %s :Module %s successfully unloaded.",user->nick.c_str(), removing->c_str(), removing->c_str()); + if (!useruid.empty()) + { + User* user = ServerInstance->FindNick(useruid); + if (user) + user->WriteNumeric(RPL_UNLOADEDMODULE, "%s %s :Module %s successfully unloaded.",user->nick.c_str(), removing->c_str(), removing->c_str()); + } + else + ServerInstance->SNO->WriteToSnoMask('A', "Module %s successfully unloaded.", removing->c_str()); rem++; } else { - if (user) - user->WriteNumeric(972, "%s %s :Failed to unload module %s: %s",user->nick.c_str(), removing->c_str(), removing->c_str(), ServerInstance->Modules->LastError().c_str()); + if (!useruid.empty()) + { + User* user = ServerInstance->FindNick(useruid); + if (user) + user->WriteNumeric(ERR_CANTUNLOADMODULE, "%s %s :Failed to unload module %s: %s",user->nick.c_str(), removing->c_str(), removing->c_str(), ServerInstance->Modules->LastError().c_str()); + } + else + ServerInstance->SNO->WriteToSnoMask('A', "Failed to unload module %s: %s", removing->c_str(), ServerInstance->Modules->LastError().c_str()); } } } @@ -1282,35 +1299,48 @@ void ServerConfig::Read(bool bail, User* user) if (ServerInstance->Modules->Load(adding->c_str())) { ServerInstance->SNO->WriteToSnoMask('A', "*** REHASH LOADED MODULE: %s",adding->c_str()); - - if (user) - user->WriteNumeric(975, "%s %s :Module %s successfully loaded.",user->nick.c_str(), adding->c_str(), adding->c_str()); + if (!useruid.empty()) + { + User* user = ServerInstance->FindNick(useruid); + if (user) + user->WriteNumeric(RPL_LOADEDMODULE, "%s %s :Module %s successfully loaded.",user->nick.c_str(), adding->c_str(), adding->c_str()); + } + else + ServerInstance->SNO->WriteToSnoMask('A', "Module %s successfully loaded.", adding->c_str()); add++; } else { - if (user) - user->WriteNumeric(974, "%s %s :Failed to load module %s: %s",user->nick.c_str(), adding->c_str(), adding->c_str(), ServerInstance->Modules->LastError().c_str()); + if (!useruid.empty()) + { + User* user = ServerInstance->FindNick(useruid); + if (user) + user->WriteNumeric(ERR_CANTLOADMODULE, "%s %s :Failed to load module %s: %s",user->nick.c_str(), adding->c_str(), adding->c_str(), ServerInstance->Modules->LastError().c_str()); + } + else + ServerInstance->SNO->WriteToSnoMask('A', "Failed to load module %s: %s", adding->c_str(), ServerInstance->Modules->LastError().c_str()); } } } ServerInstance->Logs->Log("CONFIG", DEFAULT, "Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size()); - ServerInstance->Threads->Mutex(false); + ServerInstance->Threads->Unlock(); } - /** Note: This is safe, the method checks for user == NULL */ - ServerInstance->Threads->Mutex(true); - ServerInstance->Parser->SetupCommandTable(user); - ServerInstance->Threads->Mutex(false); - - if (user) - user->WriteServ("NOTICE %s :*** Successfully rehashed server.", user->nick.c_str()); - else - ServerInstance->SNO->WriteToSnoMask('A', "*** Successfully rehashed server."); + if (!bail) + { + if (!useruid.empty()) + { + User* user = ServerInstance->FindNick(useruid); + if (user) + user->WriteServ("NOTICE %s :*** Successfully rehashed server.", user->nick.c_str()); + } + else + ServerInstance->SNO->WriteToSnoMask('A', "*** Successfully rehashed server."); + } } @@ -1319,13 +1349,13 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const char* fil { std::string line; char ch; - long linenumber; + long linenumber = 1; + long last_successful_parse = 1; bool in_tag; bool in_quote; bool in_comment; int character_count = 0; - linenumber = 1; in_tag = false; in_quote = false; in_comment = false; @@ -1428,13 +1458,19 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const char* fil if (ch != '\r') line += ch; + if ((ch != '<') && (!in_tag) && (!in_comment) && (ch > ' ') && (ch != 9)) + { + errorstream << "You have stray characters beyond the tag which starts at " << filename << ":" << last_successful_parse << std::endl; + return false; + } + if (ch == '<') { if (in_tag) { if (!in_quote) { - errorstream << "Got another opening < when the first one wasn't closed: " << filename << ":" << linenumber << std::endl; + errorstream << "The tag at location " << filename << ":" << last_successful_parse << " was valid, but there is an error in the tag which comes after it. You are possibly missing a \" or >. Please check this." << std::endl; return false; } } @@ -1442,7 +1478,7 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const char* fil { if (in_quote) { - errorstream << "We're in a quote but outside a tag, interesting. " << filename << ":" << linenumber << std::endl; + errorstream << "Parser error: Inside a quote but not within the last valid tag, which was opened at: " << filename << ":" << last_successful_parse << std::endl; return false; } else @@ -1471,11 +1507,11 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const char* fil { if (in_quote) { - errorstream << "Found a (closing) \" outside a tag: " << filename << ":" << linenumber << std::endl; + errorstream << "The tag immediately after the one at " << filename << ":" << last_successful_parse << " has a missing closing \" symbol. Please check this." << std::endl; } else { - errorstream << "Found a (opening) \" outside a tag: " << filename << ":" << linenumber << std::endl; + errorstream << "You have opened a quote (\") beyond the tag at " << filename << ":" << last_successful_parse << " without opening a new tag. Please check this." << std::endl; } } } @@ -1492,14 +1528,18 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const char* fil * If this finds an then ParseLine can simply call * LoadConf() and load the included config into the same ConfigDataHash */ - if (!this->ParseLine(target, line, linenumber, errorstream)) + long bl = linenumber; + if (!this->ParseLine(target, filename, line, linenumber, errorstream)) return false; + last_successful_parse = linenumber; + + linenumber = bl; line.clear(); } else { - errorstream << "Got a closing > when we weren't inside a tag: " << filename << ":" << linenumber << std::endl; + errorstream << "You forgot to close the tag which comes immediately after the one at " << filename << ":" << last_successful_parse << std::endl; return false; } } @@ -1522,12 +1562,13 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const std::stri return this->LoadConf(target, conf, filename.c_str(), errorstream); } -bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &linenumber, std::ostringstream &errorstream) +bool ServerConfig::ParseLine(ConfigDataHash &target, const std::string &filename, std::string &line, long &linenumber, std::ostringstream &errorstream) { std::string tagname; std::string current_key; std::string current_value; KeyValList results; + char last_char = 0; bool got_name; bool got_key; bool in_quote; @@ -1544,7 +1585,13 @@ bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &li { if (*c != '<') { - tagname += *c; + if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <='Z') || (*c >= '0' && *c <= '9') || *c == '_') + tagname += *c; + else + { + errorstream << "Invalid character in value name of tag: '" << *c << "' in value '" << tagname << "' in filename: " << filename << ":" << linenumber << std::endl; + return false; + } } } else @@ -1562,11 +1609,17 @@ bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &li if (!got_key) { /* We're still reading the key name */ - if (*c != '=') + if ((*c != '=') && (*c != '>')) { if (*c != ' ') { - current_key += *c; + if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <='Z') || (*c >= '0' && *c <= '9') || *c == '_') + current_key += *c; + else + { + errorstream << "Invalid character in key: '" << *c << "' in key '" << current_key << "' in filename: " << filename << ":" << linenumber << std::endl; + return false; + } } } else @@ -1591,16 +1644,22 @@ bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &li current_value += *c; continue; } + else if ((*c == '\\') && (!in_quote)) + { + errorstream << "You can't have an escape sequence outside of a quoted section: " << filename << ":" << linenumber << std::endl; + return false; + } else if ((*c == '\n') && (in_quote)) { /* Got a 'real' \n, treat it as part of the value */ current_value += '\n'; - linenumber++; continue; } else if ((*c == '\r') && (in_quote)) + { /* Got a \r, drop it */ continue; + } if (*c == '"') { @@ -1639,6 +1698,7 @@ bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &li { if (in_quote) { + last_char = *c; current_value += *c; } } @@ -2038,7 +2098,7 @@ bool ServerConfig::DirValid(const char* dirandfile) std::string ServerConfig::GetFullProgDir() { - char buffer[PATH_MAX+1]; + char buffer[PATH_MAX]; #ifdef WINDOWS /* Windows has specific api calls to get the exe path that never fail. * For once, windows has something of use, compared to the POSIX code @@ -2165,6 +2225,8 @@ bool InitClasses(ServerConfig* conf, const char*) delete[] n->second.cmodelist; if (n->second.umodelist) delete[] n->second.umodelist; + if (n->second.privs) + delete[] n->second.privs; } } @@ -2193,6 +2255,7 @@ bool DoClass(ServerConfig* conf, const char* tag, char**, ValueList &values, int const char* CommandList = values[1].GetString(); const char* UModeList = values[2].GetString(); const char* CModeList = values[3].GetString(); + const char *PrivsList = values[4].GetString(); for (const char* c = UModeList; *c; ++c) { @@ -2212,6 +2275,7 @@ bool DoClass(ServerConfig* conf, const char* tag, char**, ValueList &values, int conf->operclass[ClassName].commandlist = strnewdup(CommandList); conf->operclass[ClassName].umodelist = strnewdup(UModeList); conf->operclass[ClassName].cmodelist = strnewdup(CModeList); + conf->operclass[ClassName].privs = strnewdup(PrivsList); return true; } @@ -2299,10 +2363,9 @@ bool DoneELine(ServerConfig* conf, const char* tag) void ConfigReaderThread::Run() { - /* TODO: TheUser may be invalid by the time we get here! Check its validity, or pass a UID would be better */ - ServerInstance->Config->Read(do_bail, TheUser); - ServerInstance->Threads->Mutex(true); + ServerInstance->Config->Read(do_bail, TheUserUID); + ServerInstance->Threads->Lock(); this->SetExitFlag(); - ServerInstance->Threads->Mutex(false); + ServerInstance->Threads->Unlock(); }