* ---------------------------------------------------
*/
-/* $Core: libIRCDconfigreader */
+/* $Core */
/* $CopyInstall: conf/inspircd.quotes.example $(CONPATH) */
/* $CopyInstall: conf/inspircd.rules.example $(CONPATH) */
/* $CopyInstall: conf/inspircd.motd.example $(CONPATH) */
/* $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 <fstream>
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;
debugging = 0;
MaxChans = 20;
OperMaxChans = 30;
+ c_ipv4_range = 32;
+ c_ipv6_range = 128;
maxbans.clear();
DNSServerValidator = &ValidateDnsServer;
}
else
{
throw ModuleException("BufferedSocket derived class already hooked by another module");
- return false;
}
}
void ServerConfig::Send005(User* user)
{
for (std::vector<std::string>::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)
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;
}
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()))
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);
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;
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;
((*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
+ (!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 */
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 */
+ static char disabledumodes[MAXBUF]; /* Disabled usermodes */
+ static char disabledcmodes[MAXBUF]; /* Disabled chanmodes */
errstr.clear();
include_stack.clear();
{"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", "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},
{"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", "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}
};
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.c_str(), j, i->first.empty() ? "<all>" : i->first.c_str(), (unsigned long)i->second);
+ user->WriteServ("NOTICE %s :*** %d. Address: %s Reason: %s", user->nick.c_str(), j, i->first.empty() ? "<all>" : i->first.c_str(), i->second.c_str());
}
ServerInstance->Threads->Mutex(false);
}
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());
+ user->WriteNumeric(RPL_UNLOADEDMODULE, "%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.c_str(), removing->c_str(), removing->c_str(), ServerInstance->Modules->LastError().c_str());
+ 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());
}
}
}
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());
+ user->WriteNumeric(RPL_LOADEDMODULE, "%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.c_str(), adding->c_str(), adding->c_str(), ServerInstance->Modules->LastError().c_str());
+ 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());
}
}
}
}
- /** 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());
+ 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.");
+ }
}
{
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;
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;
}
}
{
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
{
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;
}
}
}
* If this finds an <include> then ParseLine can simply call
* LoadConf() and load the included config into the same ConfigDataHash
*/
+ 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;
}
}
std::string current_key;
std::string current_value;
KeyValList results;
+ char last_char = 0;
bool got_name;
bool got_key;
bool in_quote;
{
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
if (!got_key)
{
/* We're still reading the key name */
- if (*c != '=')
+ if ((*c != '=') && (*c != '>'))
{
if (*c != ' ')
{
- if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <='Z') || *c == '_')
+ if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <='Z') || (*c >= '0' && *c <= '9') || *c == '_')
current_key += *c;
else
{
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 == '"')
{
{
if (in_quote)
{
+ last_char = *c;
current_value += *c;
}
}
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