X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fconfigreader.cpp;h=8f6c93b1bf8e98baca123e7baaba2c54db5e90ba;hb=12ffb909a66401f540234aecbeeee6f94ef2fc6d;hp=2c5d01ee14f0f262686312b1ab800b1e6b5c16b0;hpb=e66e07d53efd2889e5954d30327343482d550a84;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/configreader.cpp b/src/configreader.cpp index 2c5d01ee1..8f6c93b1b 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -19,7 +19,8 @@ /* $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) */ #include "inspircd.h" #include @@ -36,7 +37,7 @@ bool DoneELine(ServerConfig* conf, const char* tag); ServerConfig::ServerConfig(InspIRCd* Instance) : ServerInstance(Instance) { this->ClearStack(); - *ServerName = *Network = *ServerDesc = *AdminName = '\0'; + *sid = *ServerName = *Network = *ServerDesc = *AdminName = '\0'; *HideWhoisServer = *AdminEmail = *AdminNick = *diepass = *restartpass = *FixedQuit = *HideKillsServer = '\0'; *DefaultModes = *CustomVersion = *motd = *rules = *PrefixQuit = *DieValue = *DNSServer = '\0'; *UserStats = *ModPath = *MyExecutable = *DisabledCommands = *PID = *SuffixQuit = '\0'; @@ -53,7 +54,8 @@ ServerConfig::ServerConfig(InspIRCd* Instance) : ServerInstance(Instance) debugging = 0; MaxChans = 20; OperMaxChans = 30; - LogLevel = DEFAULT; + c_ipv4_range = 32; + c_ipv6_range = 128; maxbans.clear(); DNSServerValidator = &ValidateDnsServer; } @@ -126,12 +128,12 @@ 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, line->c_str()); + user->WriteNumeric(005, "%s %s", user->nick.c_str(), line->c_str()); } -bool ServerConfig::CheckOnce(const char* tag) +bool ServerConfig::CheckOnce(const char* tag, ConfigDataHash &newconf) { - int count = ConfValueEnum(this->config_data, tag); + int count = ConfValueEnum(newconf, tag); if (count > 1) { @@ -253,7 +255,7 @@ bool ValidateMaxTargets(ServerConfig* conf, const char*, const char*, ValueItem { if ((data.GetInteger() < 0) || (data.GetInteger() > 31)) { - conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: value is greater than 31 or less than 0, set to 20."); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: value is greater than 31 or less than 0, set to 20."); data.Set(20); } return true; @@ -263,7 +265,7 @@ bool ValidateSoftLimit(ServerConfig* conf, const char*, const char*, ValueItem & { if ((data.GetInteger() < 1) || (data.GetInteger() > conf->GetInstance()->SE->GetMaxFds())) { - conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: value is greater than %d or less than 0, set to %d.",conf->GetInstance()->SE->GetMaxFds(),conf->GetInstance()->SE->GetMaxFds()); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: value is greater than %d or less than 0, set to %d.",conf->GetInstance()->SE->GetMaxFds(),conf->GetInstance()->SE->GetMaxFds()); data.Set(conf->GetInstance()->SE->GetMaxFds()); } return true; @@ -272,7 +274,7 @@ bool ValidateSoftLimit(ServerConfig* conf, const char*, const char*, ValueItem & bool ValidateMaxConn(ServerConfig* conf, const char*, const char*, ValueItem &data) { if (data.GetInteger() > SOMAXCONN) - conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: value may be higher than the system-defined SOMAXCONN value!"); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: value may be higher than the system-defined SOMAXCONN value!"); return true; } @@ -282,13 +284,13 @@ bool InitializeDisabledCommands(const char* data, InspIRCd* ServerInstance) std::string thiscmd; /* Enable everything first */ - for (Commandable::iterator x = ServerInstance->Parser->cmdlist.begin(); x != ServerInstance->Parser->cmdlist.end(); x++) + for (Commandtable::iterator x = ServerInstance->Parser->cmdlist.begin(); x != ServerInstance->Parser->cmdlist.end(); x++) x->second->Disable(false); /* Now disable all the ones which the user wants disabled */ while (dcmds >> thiscmd) { - Commandable::iterator cm = ServerInstance->Parser->cmdlist.find(thiscmd); + Commandtable::iterator cm = ServerInstance->Parser->cmdlist.find(thiscmd); if (cm != ServerInstance->Parser->cmdlist.end()) { cm->second->Disable(true); @@ -345,6 +347,7 @@ bool ValidateServerName(ServerConfig* conf, const char*, const char*, ValueItem std::string moo = std::string(data.GetString()).append("."); data.Set(moo.c_str()); } + conf->ValidateHostname(data.GetString(), "server", "name"); return true; } @@ -362,33 +365,12 @@ bool ValidateMaxWho(ServerConfig* conf, const char*, const char*, ValueItem &dat { if ((data.GetInteger() > 65535) || (data.GetInteger() < 1)) { - conf->GetInstance()->Logs->Log("CONFIG",DEFAULT," size out of range, setting to default of 128."); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT," size out of range, setting to default of 128."); data.Set(128); } return true; } -bool ValidateLogLevel(ServerConfig* conf, const char*, const char*, ValueItem &data) -{ - std::string dbg = data.GetString(); - conf->LogLevel = DEFAULT; - - if (dbg == "debug") - conf->LogLevel = DEBUG; - else if (dbg == "verbose") - conf->LogLevel = VERBOSE; - else if (dbg == "default") - conf->LogLevel = DEFAULT; - else if (dbg == "sparse") - conf->LogLevel = SPARSE; - else if (dbg == "none") - conf->LogLevel = NONE; - - conf->debugging = (conf->LogLevel == DEBUG); - - return true; -} - bool ValidateMotd(ServerConfig* conf, const char*, const char*, ValueItem &data) { conf->ReadFile(conf->MOTD, data.GetString()); @@ -545,7 +527,12 @@ bool DoConnect(ServerConfig* conf, const char*, char**, ValueList &values, int*) for (ClassVector::iterator item = conf->Classes.begin(); item != conf->Classes.end(); ++item) { ConnectClass* cc = *item; - if ((*name && (cc->GetName() == name)) || (*allow && (cc->GetHost() == allow)) || (*deny && (cc->GetHost() == deny))) + 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); @@ -581,6 +568,15 @@ bool DoConnect(ServerConfig* conf, const char*, char**, ValueList &values, int*) { if (*allow) { + /* 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) + { + (*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->limit = limit; cc->SetPort(port); @@ -588,6 +584,16 @@ bool DoConnect(ServerConfig* conf, const char*, char**, ValueList &values, int*) } else { + /* 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) + { + (*item)->Update(name, deny); + (*item)->SetPort(port); + return true; + } + } ConnectClass* cc = new ConnectClass(name, deny); cc->SetPort(port); conf->Classes.push_back(cc); @@ -728,11 +734,11 @@ void ServerConfig::ReportConfigError(const std::string &errormessage, bool bail, /* ":ServerInstance->Config->ServerName NOTICE user->nick :" */ if (user) { - prefixlen = strlen(this->ServerName) + strlen(user->nick) + 11; - user->WriteServ("NOTICE %s :There were errors in the configuration file:",user->nick); + 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, errors.substr(start, 510 - prefixlen).c_str()); + user->WriteServ("NOTICE %s :%s",user->nick.c_str(), errors.substr(start, 510 - prefixlen).c_str()); start += 510 - prefixlen; } } @@ -753,7 +759,6 @@ void ServerConfig::Read(bool bail, User* user) { int rem = 0, add = 0; /* Number of modules added, number of modules removed */ - static char debug[MAXBUF]; /* Temporary buffer for debugging value */ static char maxkeep[MAXBUF]; /* Temporary buffer for WhoWasMaxKeep value */ static char hidemodes[MAXBUF]; /* Modes to not allow listing from users below halfop */ static char exemptchanops[MAXBUF]; /* Exempt channel ops from these modes */ @@ -765,10 +770,32 @@ void ServerConfig::Read(bool bail, User* user) /* These tags MUST occur and must ONLY occur once in the config file */ static const char* Once[] = { "server", "admin", "files", "power", "options", NULL }; + Deprecated ChangedConfig[] = { + {"options", "hidelinks", "has been moved to as of 1.2a3"}, + {"options", "hidewhois", "has been moved to as of 1.2a3"}, + {"options", "userstats", "has been moved to as of 1.2a3"}, + {"options", "customversion", "has been moved to as of 1.2a3"}, + {"options", "hidesplits", "has been moved to as of 1.2a3"}, + {"options", "hidebans", "has been moved to as of 1.2a3"}, + {"options", "hidekills", "has been moved to as of 1.2a3"}, + {"options", "operspywhois", "has been moved to as of 1.2a3"}, + {"options", "announceinvites", "has been moved to as of 1.2a3"}, + {"options", "hidemodes", "has been moved to as of 1.2a3"}, + {"options", "maxtargets", "has been moved to as of 1.2a3"}, + {"options", "nouserdns", "has been moved to as of 1.2a3"}, + {"options", "maxwho", "has been moved to as of 1.2a3"}, + {"options", "softlimit", "has been moved to as of 1.2a3"}, + {"options", "somaxconn", "has been moved to as of 1.2a3"}, + {"options", "netbuffersize", "has been moved to as of 1.2a3"}, + {"options", "maxwho", "has been moved to as of 1.2a3"}, + {"options", "loglevel", "1.2 does not use the loglevel value. Please define tags instead."}, + {NULL, NULL, NULL} + }; + /* These tags can occur ONCE or not at all */ InitialConfig Values[] = { - {"options", "softlimit", "0", new ValueContainerUInt (&this->SoftLimit), DT_INTEGER, ValidateSoftLimit}, - {"options", "somaxconn", SOMAXCONN_S, new ValueContainerInt (&this->MaxConn), DT_INTEGER, ValidateMaxConn}, + {"performance", "softlimit", "0", new ValueContainerUInt (&this->SoftLimit), DT_INTEGER, ValidateSoftLimit}, + {"performance", "somaxconn", SOMAXCONN_S, new ValueContainerInt (&this->MaxConn), DT_INTEGER, ValidateMaxConn}, {"options", "moronbanner", "Youre banned!", new ValueContainerChar (this->MoronBanner), DT_CHARPTR, NoValidation}, {"server", "name", "", new ValueContainerChar (this->ServerName), DT_HOSTNAME|DT_BOOTONLY, ValidateServerName}, {"server", "description", "Configure Me", new ValueContainerChar (this->ServerDesc), DT_CHARPTR, NoValidation}, @@ -789,30 +816,29 @@ void ServerConfig::Read(bool bail, User* user) {"options", "prefixpart", "", new ValueContainerChar (this->PrefixPart), DT_CHARPTR, NoValidation}, {"options", "suffixpart", "", new ValueContainerChar (this->SuffixPart), DT_CHARPTR, NoValidation}, {"options", "fixedpart", "", new ValueContainerChar (this->FixedPart), DT_CHARPTR, NoValidation}, - {"options", "loglevel", "default", new ValueContainerChar (debug), DT_CHARPTR, ValidateLogLevel}, - {"options", "netbuffersize","10240", new ValueContainerInt (&this->NetBufferSize), DT_INTEGER, ValidateNetBufferSize}, - {"options", "maxwho", "128", new ValueContainerInt (&this->MaxWhoResults), DT_INTEGER, ValidateMaxWho}, + {"performance", "netbuffersize","10240", new ValueContainerInt (&this->NetBufferSize), DT_INTEGER, ValidateNetBufferSize}, + {"performance", "maxwho", "128", new ValueContainerInt (&this->MaxWhoResults), DT_INTEGER, ValidateMaxWho}, {"options", "allowhalfop", "0", new ValueContainerBool (&this->AllowHalfop), DT_BOOLEAN, NoValidation}, {"dns", "server", "", new ValueContainerChar (this->DNSServer), DT_IPADDRESS,DNSServerValidator}, {"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}, - {"options", "userstats", "", new ValueContainerChar (this->UserStats), DT_CHARPTR, NoValidation}, - {"options", "customversion","", new ValueContainerChar (this->CustomVersion), DT_CHARPTR, NoValidation}, - {"options", "hidesplits", "0", new ValueContainerBool (&this->HideSplits), DT_BOOLEAN, NoValidation}, - {"options", "hidebans", "0", new ValueContainerBool (&this->HideBans), DT_BOOLEAN, NoValidation}, - {"options", "hidewhois", "", new ValueContainerChar (this->HideWhoisServer), DT_NOSPACES, NoValidation}, - {"options", "hidekills", "", new ValueContainerChar (this->HideKillsServer), DT_NOSPACES, NoValidation}, - {"options", "operspywhois", "0", new ValueContainerBool (&this->OperSpyWhois), DT_BOOLEAN, NoValidation}, - {"options", "nouserdns", "0", new ValueContainerBool (&this->NoUserDns), DT_BOOLEAN, 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}, + {"security", "hidebans", "0", new ValueContainerBool (&this->HideBans), DT_BOOLEAN, NoValidation}, + {"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}, + {"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}, {"options", "ircumsgprefix","0", new ValueContainerBool (&this->UndernetMsgPrefix), DT_BOOLEAN, NoValidation}, - {"options", "announceinvites", "1", new ValueContainerChar (announceinvites), DT_CHARPTR, ValidateInvite}, + {"security", "announceinvites", "1", new ValueContainerChar (announceinvites), DT_CHARPTR, ValidateInvite}, {"options", "hostintopic", "1", new ValueContainerBool (&this->FullHostInTopic), DT_BOOLEAN, NoValidation}, - {"options", "hidemodes", "", new ValueContainerChar (hidemodes), DT_CHARPTR, ValidateModeLists}, + {"security", "hidemodes", "", new ValueContainerChar (hidemodes), DT_CHARPTR, ValidateModeLists}, {"options", "exemptchanops","", new ValueContainerChar (exemptchanops), DT_CHARPTR, ValidateExemptChanOps}, - {"options", "maxtargets", "20", new ValueContainerUInt (&this->MaxTargets), DT_INTEGER, ValidateMaxTargets}, + {"security", "maxtargets", "20", new ValueContainerUInt (&this->MaxTargets), DT_INTEGER, ValidateMaxTargets}, {"options", "defaultmodes", "nt", new ValueContainerChar (this->DefaultModes), DT_CHARPTR, NoValidation}, {"pid", "file", "", new ValueContainerChar (this->PID), DT_CHARPTR, NoValidation}, {"whowas", "groupsize", "10", new ValueContainerInt (&this->WhoWasGroupSize), DT_INTEGER, NoValidation}, @@ -821,9 +847,21 @@ 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}, + {"limits", "maxident", "11", new ValueContainerST (&this->Limits.IdentMax), DT_INTEGER, NoValidation}, + {"limits", "maxquit", "255", new ValueContainerST (&this->Limits.MaxQuit), DT_INTEGER, NoValidation}, + {"limits", "maxtopic", "307", new ValueContainerST (&this->Limits.MaxTopic), DT_INTEGER, NoValidation}, + {"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}, {NULL, NULL, NULL, NULL, DT_NOTHING, NoValidation} }; + /* These tags can occur multiple times, and therefore they have special code to read them * which is different to the code for reading the singular tags listed above. */ @@ -911,14 +949,7 @@ 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 we succeeded, set the ircd config to the new one */ - ServerInstance->Threads->Mutex(true); - this->config_data = newconfig; - ServerInstance->Threads->Mutex(false); - } - else + if (!this->DoInclude(newconfig, ServerInstance->ConfigFileName, errstr)) { ReportConfigError(errstr.str(), bail, user); return; @@ -930,12 +961,22 @@ void ServerConfig::Read(bool bail, User* user) /* Check we dont have more than one of singular tags, or any of them missing */ for (int Index = 0; Once[Index]; Index++) - if (!CheckOnce(Once[Index])) + if (!CheckOnce(Once[Index], newconfig)) return; + for (int Index = 0; ChangedConfig[Index].tag; Index++) + { + char item[MAXBUF]; + *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. */ - for (int Index = 0; Values[Index].tag; Index++) + for (int Index = 0; Values[Index].tag; ++Index) { char item[MAXBUF]; int dt = Values[Index].datatype; @@ -950,7 +991,7 @@ void ServerConfig::Read(bool bail, User* user) if (bootonly && !bail) continue; - ConfValue(this->config_data, Values[Index].tag, Values[Index].value, Values[Index].default_value, 0, item, MAXBUF, allow_newlines); + ConfValue(newconfig, Values[Index].tag, Values[Index].value, Values[Index].default_value, 0, item, MAXBUF, allow_newlines); ValueItem vi(item); if (!Values[Index].validation_function(this, Values[Index].tag, Values[Index].value, vi)) @@ -971,7 +1012,6 @@ void ServerConfig::Read(bool bail, User* user) ValueContainerChar* vcc = (ValueContainerChar*)Values[Index].val; this->ValidateHostname(vi.GetString(), Values[Index].tag, Values[Index].value); vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); - ServerInstance->Logs->Log("CONFIG",DEFAULT,"Got %s", vi.GetString()); } break; case DT_IPADDRESS: @@ -984,7 +1024,7 @@ void ServerConfig::Read(bool bail, User* user) case DT_CHANNEL: { ValueContainerChar* vcc = (ValueContainerChar*)Values[Index].val; - if (*(vi.GetString()) && !ServerInstance->IsChannel(vi.GetString())) + if (*(vi.GetString()) && !ServerInstance->IsChannel(vi.GetString(), MAXBUF)) { ServerInstance->Threads->Mutex(false); throw CoreException("The value of <"+std::string(Values[Index].tag)+":"+Values[Index].value+"> is not a valid channel name"); @@ -1026,18 +1066,18 @@ void ServerConfig::Read(bool bail, User* user) * and call the callbacks associated with them. We have three * callbacks for these, a 'start', 'item' and 'end' callback. */ - for (int Index = 0; MultiValues[Index].tag; Index++) + for (int Index = 0; MultiValues[Index].tag; ++Index) { ServerInstance->Threads->Mutex(true); MultiValues[Index].init_function(this, MultiValues[Index].tag); ServerInstance->Threads->Mutex(false); - int number_of_tags = ConfValueEnum(this->config_data, MultiValues[Index].tag); + int number_of_tags = ConfValueEnum(newconfig, MultiValues[Index].tag); - for (int tagnum = 0; tagnum < number_of_tags; tagnum++) + for (int tagnum = 0; tagnum < number_of_tags; ++tagnum) { ValueList vl; - for (int valuenum = 0; MultiValues[Index].items[valuenum]; valuenum++) + for (int valuenum = 0; (MultiValues[Index].items[valuenum]) && (valuenum < MAX_VALUES_PER_TAG); ++valuenum) { int dt = MultiValues[Index].datatype[valuenum]; bool allow_newlines = ((dt & DT_ALLOW_NEWLINE) > 0); @@ -1055,7 +1095,7 @@ void ServerConfig::Read(bool bail, User* user) case DT_NOSPACES: { char item[MAXBUF]; - if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + if (ConfValue(newconfig, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) vl.push_back(ValueItem(item)); else vl.push_back(ValueItem("")); @@ -1065,7 +1105,7 @@ void ServerConfig::Read(bool bail, User* user) case DT_HOSTNAME: { char item[MAXBUF]; - if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + if (ConfValue(newconfig, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) vl.push_back(ValueItem(item)); else vl.push_back(ValueItem("")); @@ -1075,7 +1115,7 @@ void ServerConfig::Read(bool bail, User* user) case DT_IPADDRESS: { char item[MAXBUF]; - if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + if (ConfValue(newconfig, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) vl.push_back(ValueItem(item)); else vl.push_back(ValueItem("")); @@ -1085,18 +1125,18 @@ void ServerConfig::Read(bool bail, User* user) case DT_CHANNEL: { char item[MAXBUF]; - if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + if (ConfValue(newconfig, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) vl.push_back(ValueItem(item)); else vl.push_back(ValueItem("")); - if (!ServerInstance->IsChannel(vl[vl.size()-1].GetString())) + if (!ServerInstance->IsChannel(vl[vl.size()-1].GetString(), MAXBUF)) throw CoreException("The value of <"+std::string(MultiValues[Index].tag)+":"+MultiValues[Index].items[valuenum]+"> number "+ConvToStr(tagnum + 1)+" is not a valid channel name"); } break; case DT_CHARPTR: { char item[MAXBUF]; - if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + if (ConfValue(newconfig, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) vl.push_back(ValueItem(item)); else vl.push_back(ValueItem("")); @@ -1105,7 +1145,7 @@ void ServerConfig::Read(bool bail, User* user) case DT_INTEGER: { int item = 0; - if (ConfValueInteger(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item)) + if (ConfValueInteger(newconfig, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item)) vl.push_back(ValueItem(item)); else vl.push_back(ValueItem(0)); @@ -1113,7 +1153,7 @@ void ServerConfig::Read(bool bail, User* user) break; case DT_BOOLEAN: { - bool item = ConfValueBool(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum); + bool item = ConfValueBool(newconfig, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum); vl.push_back(ValueItem(item)); } break; @@ -1134,6 +1174,11 @@ void ServerConfig::Read(bool bail, User* user) MultiValues[Index].finish_function(this, MultiValues[Index].tag); } + /* Finalise the limits, increment them all by one so that we can just put assign(str, 0, val) + * rather than assign(str, 0, val + 1) + */ + Limits.Finalise(); + } catch (CoreException &ce) @@ -1142,15 +1187,56 @@ void ServerConfig::Read(bool bail, User* user) return; } + ServerInstance->Threads->Mutex(true); + for (int i = 0; i < ConfValueEnum(newconfig, "type"); ++i) + { + char item[MAXBUF], classn[MAXBUF], classes[MAXBUF]; + std::string classname; + ConfValue(newconfig, "type", "classes", "", i, classes, MAXBUF, false); + irc::spacesepstream str(classes); + ConfValue(newconfig, "type", "name", "", i, item, MAXBUF, false); + while (str.GetToken(classname)) + { + std::string lost; + bool foundclass = false; + for (int j = 0; j < ConfValueEnum(newconfig, "class"); ++j) + { + ConfValue(newconfig, "class", "name", "", j, classn, MAXBUF, false); + if (!strcmp(classn, classname.c_str())) + { + foundclass = true; + break; + } + } + 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()); + else + { + if (bail) + printf("Warning: Oper type '%s' has a missing class named '%s', this does nothing!\n", item, classname.c_str()); + else + ServerInstance->SNO->WriteToSnoMask('A', "Warning: Oper type '%s' has a missing class named '%s', this does nothing!", item, classname.c_str()); + } + } + } + } + + /* If we succeeded, set the ircd config to the new one */ + this->config_data = newconfig; + + ServerInstance->Threads->Mutex(false); + // write once here, to try it out and make sure its ok ServerInstance->WritePID(this->PID); - ServerInstance->Log(DEFAULT,"Done reading configuration file."); - /* Switch over logfiles */ ServerInstance->Logs->CloseLogs(); ServerInstance->Logs->OpenFileLogs(); + ServerInstance->Logs->Log("CONFIG", DEFAULT, "Done reading configuration file."); + /* If we're rehashing, let's load any new modules, and unload old ones */ if (!bail) @@ -1162,12 +1248,12 @@ void ServerConfig::Read(bool bail, User* user) if (pl.size() && user) { ServerInstance->Threads->Mutex(true); - user->WriteServ("NOTICE %s :*** Not all your client ports could be bound.", user->nick); - user->WriteServ("NOTICE %s :*** The following port(s) failed to bind:", user->nick); + 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. IP: %s Port: %lu", user->nick, j, i->first.empty() ? "" : i->first.c_str(), (unsigned long)i->second); + 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); } ServerInstance->Threads->Mutex(false); } @@ -1182,14 +1268,14 @@ 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, removing->c_str(), removing->c_str()); + user->WriteNumeric(973, "%s %s :Module %s successfully unloaded.",user->nick.c_str(), removing->c_str(), removing->c_str()); rem++; } else { if (user) - user->WriteNumeric(972, "%s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ServerInstance->Modules->LastError().c_str()); + 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()); } } } @@ -1203,33 +1289,38 @@ void ServerConfig::Read(bool bail, User* user) ServerInstance->SNO->WriteToSnoMask('A', "*** REHASH LOADED MODULE: %s",adding->c_str()); if (user) - user->WriteNumeric(975, "%s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str()); + user->WriteNumeric(975, "%s %s :Module %s successfully loaded.",user->nick.c_str(), adding->c_str(), adding->c_str()); add++; } else { if (user) - user->WriteNumeric(974, "%s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ServerInstance->Modules->LastError().c_str()); + 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()); } } } - ServerInstance->Log(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->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); } - /** 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); + if (bail) + { + /** Note: This is safe, the method checks for user == NULL */ + ServerInstance->Threads->Mutex(true); + ServerInstance->Parser->SetupCommandTable(user); + ServerInstance->Threads->Mutex(false); + } else - ServerInstance->SNO->WriteToSnoMask('A', "*** Successfully rehashed server."); + { + if (user) + user->WriteServ("NOTICE %s :*** Successfully rehashed server.", user->nick.c_str()); + else + ServerInstance->SNO->WriteToSnoMask('A', "*** Successfully rehashed server."); + } } @@ -1238,13 +1329,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; @@ -1271,9 +1362,8 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const char* fil include_stack.push_back(filename); /* Start reading characters... */ - while (!feof(conf)) + while ((ch = fgetc(conf)) != EOF) { - ch = fgetc(conf); /* * Fix for moronic windows issue spotted by Adremelech. * Some windows editors save text files as utf-16, which is @@ -1348,13 +1438,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; } } @@ -1362,7 +1458,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 @@ -1391,35 +1487,39 @@ 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; } } } else if (ch == '>') { + if (!in_quote) { if (in_tag) { // errorstream << "Closing config tag on line " << linenumber << std::endl; in_tag = false; - + /* * 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; } } @@ -1442,12 +1542,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; @@ -1464,7 +1565,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 @@ -1482,11 +1589,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 @@ -1511,16 +1624,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 == '"') { @@ -1559,6 +1678,7 @@ bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &li { if (in_quote) { + last_char = *c; current_value += *c; } } @@ -1588,6 +1708,11 @@ bool ServerConfig::DoPipe(ConfigDataHash &target, const std::string &file, std:: return ret; } +bool ServerConfig::StartsWithWindowsDriveLetter(const std::string &path) +{ + return (path.length() > 2 && isalpha(path[0]) && path[1] == ':'); +} + bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream) { std::string confpath; @@ -1600,7 +1725,7 @@ bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, st std::replace(newfile.begin(),newfile.end(),'\\','/'); std::replace(confpath.begin(),confpath.end(),'\\','/'); - if ((newfile[0] != '/') && (newfile.find("://") == std::string::npos)) + if ((newfile[0] != '/') && (!StartsWithWindowsDriveLetter(newfile))) { if((pos = confpath.rfind("/")) != std::string::npos) { @@ -1680,7 +1805,7 @@ bool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, con return true; } } - else if(pos == 0) + else if (pos == 0) { if (!default_value.empty()) { @@ -1822,17 +1947,19 @@ bool ServerConfig::ReadFile(file_cache &F, const char* fname) F.clear(); - if ((*fname != '/') && (*fname != '\\')) + if ((*fname != '/') && (*fname != '\\') && (!StartsWithWindowsDriveLetter(fname))) { std::string::size_type pos; std::string confpath = ServerInstance->ConfigFileName; std::string newfile = fname; - if ((pos = confpath.rfind("/")) != std::string::npos) + if (((pos = confpath.rfind("/"))) != std::string::npos) newfile = confpath.substr(0, pos) + std::string("/") + fname; - else if ((pos = confpath.rfind("\\")) != std::string::npos) + else if (((pos = confpath.rfind("\\"))) != std::string::npos) newfile = confpath.substr(0, pos) + std::string("\\") + fname; + ServerInstance->Logs->Log("config", DEBUG, "Filename: %s", newfile.c_str()); + if (!FileExists(newfile.c_str())) return false; file = fopen(newfile.c_str(), "r"); @@ -1853,10 +1980,7 @@ bool ServerConfig::ReadFile(file_cache &F, const char* fname) else *linebuf = 0; - if (!feof(file)) - { - F.push_back(*linebuf ? linebuf : " "); - } + F.push_back(*linebuf ? linebuf : " "); } fclose(file); @@ -1898,7 +2022,7 @@ bool ServerConfig::DirValid(const char* dirandfile) { #ifdef WINDOWS return true; -#endif +#else char work[1024]; char buffer[1024]; @@ -1949,11 +2073,12 @@ bool ServerConfig::DirValid(const char* dirandfile) { return false; } +#endif } 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