bool ValidateServerName(ServerConfig* conf, const char*, const char*, ValueItem &data)
{
+ conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Validating server name");
/* If we already have a servername, and they changed it, we should throw an exception. */
- if ((strcasecmp(conf->ServerName, data.GetString())) && (*conf->ServerName))
- {
- throw CoreException("Configuration error: You cannot change your servername at runtime! Please restart your server for this change to be applied.");
- /* We don't actually reach this return of course... */
- return false;
- }
- if (!strchr(data.GetString(),'.'))
+ if (!strchr(data.GetString(), '.'))
{
conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: <server:name> '%s' is not a fully-qualified domain name. Changed to '%s%c'",data.GetString(),data.GetString(),'.');
std::string moo = std::string(data.GetString()).append(".");
bool ValidateSID(ServerConfig* conf, const char*, const char*, ValueItem &data)
{
+ conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Validating server id");
+
const char *sid = data.GetString();
if (*sid && !conf->GetInstance()->IsSID(sid))
throw CoreException(std::string(sid) + " is not a valid server ID. A server ID must be 3 characters long, with the first character a digit and the next two characters a digit or letter.");
}
+ strlcpy(conf->sid, sid, 5);
+
return true;
}
{
conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Reading connect classes...");
- for (ClassVector::iterator i = conf->Classes.begin(); i != conf->Classes.end(); i++)
- {
- ConnectClass *c = *i;
-
- conf->GetInstance()->Logs->Log("CONFIG",DEBUG, "Address of class is %p", c);
- }
-
for (ClassVector::iterator i = conf->Classes.begin(); i != conf->Classes.end() ; )
{
ConnectClass* c = *i;
{"options", "softlimit", MAXCLIENTS_S, new ValueContainerUInt (&this->SoftLimit), DT_INTEGER, ValidateSoftLimit},
{"options", "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, ValidateServerName},
+ {"server", "name", "", new ValueContainerChar (this->ServerName), DT_HOSTNAME|DT_BOOTONLY, ValidateServerName},
{"server", "description", "Configure Me", new ValueContainerChar (this->ServerDesc), DT_CHARPTR, NoValidation},
{"server", "network", "Network", new ValueContainerChar (this->Network), DT_NOSPACES, NoValidation},
- {"server", "id", "", new ValueContainerChar (this->sid), DT_CHARPTR, ValidateSID},
+ {"server", "id", "", new ValueContainerChar (this->sid), DT_CHARPTR|DT_BOOTONLY, ValidateSID},
{"admin", "name", "", new ValueContainerChar (this->AdminName), DT_CHARPTR, NoValidation},
{"admin", "email", "Mis@configu.red", new ValueContainerChar (this->AdminEmail), DT_CHARPTR, NoValidation},
{"admin", "nick", "Misconfigured", new ValueContainerChar (this->AdminNick), DT_CHARPTR, NoValidation},
/* Make a copy here so if it fails then we can carry on running with an unaffected config */
newconfig.clear();
- if (this->LoadConf(newconfig, ServerInstance->ConfigFileName, errstr))
+ 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
{
int dt = Values[Index].datatype;
bool allow_newlines = ((dt & DT_ALLOW_NEWLINE) > 0);
bool allow_wild = ((dt & DT_ALLOW_WILD) > 0);
+ bool bootonly = ((dt & DT_BOOTONLY) > 0);
dt &= ~DT_ALLOW_NEWLINE;
dt &= ~DT_ALLOW_WILD;
+ dt &= ~DT_BOOTONLY;
+
+ /* Silently ignore boot only values */
+ if (bootonly && !bail)
+ continue;
ConfValue(this->config_data, 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))
throw CoreException("One or more values in your configuration file failed to validate. Please see your ircd.log for more information.");
- switch (Values[Index].datatype)
+ ServerInstance->Threads->Mutex(true);
+ switch (dt)
{
case DT_NOSPACES:
{
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:
{
ValueContainerChar* vcc = (ValueContainerChar*)Values[Index].val;
if (*(vi.GetString()) && !ServerInstance->IsChannel(vi.GetString()))
+ {
+ ServerInstance->Threads->Mutex(false);
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);
}
break;
}
/* We're done with this now */
delete Values[Index].val;
+ ServerInstance->Threads->Mutex(false);
}
/* Read the multiple-tag items (class tags, connect tags, etc)
*/
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);
dt &= ~DT_ALLOW_NEWLINE;
dt &= ~DT_ALLOW_WILD;
- switch (dt)
+ ServerInstance->Threads->Mutex(true);
+ /* We catch and rethrow any exception here just so we can free our mutex
+ */
+ try
{
- 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))
- vl.push_back(ValueItem(item));
- else
- vl.push_back(ValueItem(""));
- this->ValidateNoSpaces(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]);
- }
- break;
- 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))
- vl.push_back(ValueItem(item));
- else
- vl.push_back(ValueItem(""));
- this->ValidateHostname(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]);
- }
- break;
- 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))
- vl.push_back(ValueItem(item));
- else
- vl.push_back(ValueItem(""));
- this->ValidateIP(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum], allow_wild);
- }
- break;
- 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))
- vl.push_back(ValueItem(item));
- else
- vl.push_back(ValueItem(""));
- if (!ServerInstance->IsChannel(vl[vl.size()-1].GetString()))
- 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))
- vl.push_back(ValueItem(item));
- else
- vl.push_back(ValueItem(""));
- }
- break;
- case DT_INTEGER:
+ switch (dt)
{
- int item = 0;
- if (ConfValueInteger(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item))
+ 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))
+ vl.push_back(ValueItem(item));
+ else
+ vl.push_back(ValueItem(""));
+ this->ValidateNoSpaces(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]);
+ }
+ break;
+ 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))
+ vl.push_back(ValueItem(item));
+ else
+ vl.push_back(ValueItem(""));
+ this->ValidateHostname(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]);
+ }
+ break;
+ 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))
+ vl.push_back(ValueItem(item));
+ else
+ vl.push_back(ValueItem(""));
+ this->ValidateIP(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum], allow_wild);
+ }
+ break;
+ 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))
+ vl.push_back(ValueItem(item));
+ else
+ vl.push_back(ValueItem(""));
+ if (!ServerInstance->IsChannel(vl[vl.size()-1].GetString()))
+ 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))
+ vl.push_back(ValueItem(item));
+ else
+ vl.push_back(ValueItem(""));
+ }
+ break;
+ 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))
+ vl.push_back(ValueItem(item));
+ else
+ vl.push_back(ValueItem(0));
+ }
+ break;
+ case DT_BOOLEAN:
+ {
+ bool item = ConfValueBool(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum);
vl.push_back(ValueItem(item));
- else
- vl.push_back(ValueItem(0));
- }
- break;
- case DT_BOOLEAN:
- {
- bool item = ConfValueBool(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum);
- vl.push_back(ValueItem(item));
+ }
+ break;
+ default:
+ /* Someone was smoking craq if we got here, and we're all gonna die. */
+ break;
}
- break;
- default:
- /* Someone was smoking craq if we got here, and we're all gonna die. */
- break;
}
+ catch (CoreException &e)
+ {
+ ServerInstance->Threads->Mutex(false);
+ throw e;
+ }
+ ServerInstance->Threads->Mutex(false);
}
- MultiValues[Index].validation_function(this, MultiValues[Index].tag, (char**)MultiValues[Index].items, vl, MultiValues[Index].datatype);
+ MultiValues[Index].validation_function(this, MultiValues[Index].tag, (char**)MultiValues[Index].items, vl, MultiValues[Index].datatype);
}
- MultiValues[Index].finish_function(this, MultiValues[Index].tag);
+ MultiValues[Index].finish_function(this, MultiValues[Index].tag);
}
}
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);
int j = 1;
{
user->WriteServ("NOTICE %s :*** %d. IP: %s Port: %lu", user->nick, j, i->first.empty() ? "<all>" : i->first.c_str(), (unsigned long)i->second);
}
+ ServerInstance->Threads->Mutex(false);
}
+ ServerInstance->Threads->Mutex(true);
if (!removed_modules.empty())
{
for (std::vector<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)
}
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->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);
}
-bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::ostringstream &errorstream)
+bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const char* filename, std::ostringstream &errorstream)
{
- std::ifstream conf(filename);
std::string line;
char ch;
long linenumber;
in_quote = false;
in_comment = false;
+ ServerInstance->Logs->Log("CONFIG", DEBUG, "Reading %s", filename);
+
/* Check if the file open failed first */
if (!conf)
{
return false;
}
- /* Fix the chmod of the file to restrict it to the current user and group */
- chmod(filename,0600);
-
for (unsigned int t = 0; t < include_stack.size(); t++)
{
if (std::string(filename) == include_stack[t])
include_stack.push_back(filename);
/* Start reading characters... */
- while (conf.get(ch))
+ while (!feof(conf))
{
-
+ ch = fgetc(conf);
/*
* Fix for moronic windows issue spotted by Adremelech.
* Some windows editors save text files as utf-16, which is
{
line += ch;
char real_character;
- if (conf.get(real_character))
+ if (!feof(conf))
{
+ real_character = fgetc(conf);
if (real_character == 'n')
real_character = '\n';
line += real_character;
}
-bool ServerConfig::LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream)
+bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const std::string &filename, std::ostringstream &errorstream)
{
- return this->LoadConf(target, filename.c_str(), errorstream);
+ return this->LoadConf(target, conf, filename.c_str(), errorstream);
}
bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &linenumber, std::ostringstream &errorstream)
if (!this->DoInclude(target, current_value, errorstream))
return false;
}
+ else if ((tagname == "include") && (current_key == "executable"))
+ {
+ /* Pipe an executable and use its stdout as config data */
+ if (!this->DoPipe(target, current_value, errorstream))
+ return false;
+ }
current_key.clear();
current_value.clear();
return true;
}
+bool ServerConfig::DoPipe(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream)
+{
+ FILE* conf = popen(file.c_str(), "r");
+ bool ret = false;
+
+ if (conf)
+ {
+ ret = LoadConf(target, conf, file.c_str(), errorstream);
+ pclose(conf);
+ }
+ else
+ errorstream << "Couldn't execute: " << file << std::endl;
+
+ return ret;
+}
+
bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream)
{
std::string confpath;
}
}
- return LoadConf(target, newfile, errorstream);
+ FILE* conf = fopen(newfile.c_str(), "r");
+ bool ret = false;
+
+ if (conf)
+ {
+ ret = LoadConf(target, conf, newfile, errorstream);
+ fclose(conf);
+ }
+ else
+ errorstream << "Couldn't open config file: " << file << std::endl;
+
+ return ret;
}
bool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length, bool allow_linefeeds)
{
/* 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);
+ this->SetExitFlag();
+ ServerInstance->Threads->Mutex(false);
}