// UtilityConfig.cpp // // Copyright (C) 2011, ARM Research Labs, LLC. // See www.armresearch.com for the copyright terms. // // This file implements the common functionality for the configuration // utilities. #include #include #include #include #include #include #include #include #include #include #include #include "UtilityConfig.hpp" using namespace std; ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Configuration. //////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Initialize sample ignore list file path. #ifdef WIN // Windows OS. const std::string UtilityConfig::SampleIgnoreListFile("C:\\SNF\\GBUdbIgnoreList.txt.sample"); #else #ifdef DEFAULT_DATA_DIR // *nix, DEFAULT_DATA_DIR is specified on the compile command line. const std::string UtilityConfig::SampleIgnoreListFile(DEFAULT_DATA_DIR "/GBUdbIgnoreList.txt.sample"); #else // Not Windows, and DEFAULT_DATA_DIR is not specified on the compile // command line. In this case, we don't know the path for the sample // ignore list file. #error DEFAULT_DATA_DIR must be defined by -DDEFAULT_DATA_DIR="..." when compiling. #endif #endif // Initialize sample rulebase script file. #ifdef WIN // Windows OS. const std::string UtilityConfig::SampleRulebaseScriptFile("C:\\SNF\\getRulebase.sample"); #else #ifdef SBIN_DIR // *nix, SBIN_DIR is specified on the compile command line. const std::string UtilityConfig::SampleRulebaseScriptFile(SBIN_DIR "/getRulebase.sample"); #else // Not Windows, and SBIN_DIR is not specified on the compile // command line. In this case, we don't know the path for the sample // ignore list file. #error SBIN_DIR must be defined by -DSBIN_DIR="..." when compiling. #endif #endif // Initialize OS-specific values. #ifdef WIN // Windows OS. const std::string UtilityConfig::OperatingSystemType("Windows"); const std::string DirectorySeparator("\\"); #else const std::string DirectorySeparator("/"); #ifdef SNF_OSTYPE // *nix, SNF_OSTYPE is specified on the compile command line. const std::string UtilityConfig::OperatingSystemType(SNF_OSTYPE); #else // Not Windows, and SNF_OSTYPE is not specified on the compile command // line. In this case, we don't know the operating system. #error SNF_OSTYPE must be defined by -DSNF_OSTYPE="..." when compiling. #endif #endif /// SNF user name. const string SNFUserName = "snfuser"; /// SNF group name. const string SNFGroupName = "snfuser"; /// Verbose command-line input. const string VerboseKey("-v"); /// Explain command-line input. const string ExplainKey("-explain"); /// Help command-line input. const string HelpKey("-h"); const std::string UtilityConfig::BackupSuffix("_snf_backup"); ////////////////////////////////////////////////////////////////////////////////////////////////////////// // End of configuration. ///////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// UtilityConfig::UtilityConfig() : ExplainRequested(false), VerboseRequested(false), HelpRequested(false) { } bool UtilityConfig::FileExists(const std::string File) { if (Verbose()) { cout << "Check whether " << File << " exists..."; } struct stat StatBuf; if (0 != stat(File.c_str(), &StatBuf)) { // Error checking whether file exists. if (ENOENT == errno) { // Doesn't exist. OutputVerboseEnd(); return false; } string Temp; // Other error from stat(). Temp = "Error getting info for file " + File; Temp += ": "; Temp += strerror(errno); throw runtime_error(Temp); } OutputVerboseEnd(); return true; } void UtilityConfig::CheckAndLoadConfigFile(const std::string DefaultFile[], int NumDefaultFiles) { string ProvisionalConfigFile = ConfigFile; if (ProvisionalConfigFile.length() == 0) { int i; vector FoundFile; for (i = 0; i < NumDefaultFiles; i++) { if (!FileExists(DefaultFile[i])) { continue; // File doesn't exist. } FoundFile.push_back(DefaultFile[i]); // Update list of found files. ProvisionalConfigFile = DefaultFile[i]; // Found configuration file. } if (0 == FoundFile.size()) { // No default file found. string Temp; Temp = "Configuration file was not specified, and no default configuration file was found. "; Temp += "Checked:\n\n"; for (i = 0; i < NumDefaultFiles; i++) { Temp += " "; Temp += DefaultFile[i] + "\n"; } throw runtime_error(Temp); } if (FoundFile.size() > 1) { // No default file found. string Temp; Temp = "Configuration file was not specified, and more than one default configuration file was found::\n\n"; for (i = 0; i < FoundFile.size(); i++) { Temp += " "; Temp += FoundFile[i] + "\n"; } throw runtime_error(Temp); } } LoadConfigFile(ProvisionalConfigFile); } void UtilityConfig::LoadConfigFile(std::string Name) { SetConfigFileName(Name); if (Verbose()) { cout << "Using configuration file " << ConfigFile << ".\n"; } // Load the data. try { CFGData.initializeFromFile(GetConfigFileName().c_str()); } catch(...) { string Temp; Temp = "Error reading configuration file " + GetConfigFileName(); Temp += "."; throw runtime_error(Temp); } if ( (CFGData.paths_workspace_path.length() == 0) || (CFGData.paths_rulebase_path.length() == 0) || (CFGData.paths_log_path.length() == 0) || (CFGData.update_script_call.length() == 0) || (CFGData.node_identity.length() == 0) ) { string Temp; Temp = "The configuration file " + GetConfigFileName(); Temp += " did not have the necessary specification of one or more paths:\n"; Temp += "\n Workspace path: " + CFGData.paths_workspace_path; Temp += "\n Rulebase path: " + CFGData.paths_rulebase_path; Temp += "\n Log path: " + CFGData.paths_log_path; Temp += "\n Update script: " + CFGData.update_script_call; Temp += "\n Identity file: " + CFGData.node_identity; throw runtime_error(Temp); } } string UtilityConfig::GetPlatformContents(void) { return CFGData.PlatformElementContents; } string UtilityConfig::GetConfigFileName(void) { return ConfigFile; } void UtilityConfig::SetConfigFileName(string Name) { ConfigFile = Name; } string UtilityConfig::GetWorkspacePath(void) { return CFGData.paths_workspace_path; } string UtilityConfig::GetRulebasePath(void) { return CFGData.paths_rulebase_path; } string UtilityConfig::GetLogPath(void) { return CFGData.paths_log_path; } string UtilityConfig::GetIdentityFileName(void) { return CFGData.node_identity; } string UtilityConfig::GetRulebaseScriptName(void) { return CFGData.update_script_call; } void UtilityConfig::Copy(std::string From, std::string To) { if (Verbose()) { cout << "Copy " << From << " to " << To << "..."; } if (!Explain()) { ifstream Input; Input.open(From.c_str()); // Read the contents. if (!Input) { string Temp; Temp = "Error opening the file " + From; Temp += " to copy from: "; Temp += strerror(errno); throw runtime_error(Temp); } string Content; string Line; while (getline(Input, Line)) { Content += Line + "\n"; // Copy this line. } if (!Input.eof()) { // Should be at end-of-file. string Temp; Temp = "Error reading the " + From; Temp += " to copy from: "; Temp += strerror(errno); throw runtime_error(Temp); } Input.close(); if (Input.bad()) { string Temp; Temp = "Error closing the file " + From; Temp += " to copy from: "; Temp += strerror(errno); throw runtime_error(Temp); } ofstream Output; // Write the contents. Output.open(To.c_str(), ios::trunc); if (!Output) { string Temp; Temp = "Error opening the file " + To; Temp += " to copy to: "; Temp += strerror(errno); throw runtime_error(Temp); } Output << Content; if (!Output) { string Temp; Temp = "Error writing the file " + To; Temp += " to copy to: "; Temp += strerror(errno); throw runtime_error(Temp); } Output.close(); if (!Output) { string Temp; Temp = "Error closing the file " + To; Temp += " to copy to: "; Temp += strerror(errno); throw runtime_error(Temp); } } OutputVerboseEnd(); } void UtilityConfig::SetOwnerGroup(std::string &File) { struct passwd *SNFPasswd; uid_t SNFUid; struct group *SNFGroup; gid_t SNFGid; if (Verbose()) { cout << "Set owner:group of " << File << " to " << SNFUserName << ":" << SNFGroupName << "..."; } if (!Explain()) { SNFPasswd = getpwnam(SNFUserName.c_str()); if (SNFPasswd == 0) { string Temp; Temp = "Error getting info for Sniffer user " + SNFUserName; Temp += ": "; Temp += strerror(errno); throw runtime_error(Temp); } SNFUid = SNFPasswd->pw_uid; SNFGid = SNFPasswd->pw_gid; if (chown(File.c_str(), SNFUid, SNFGid) != 0) { string Temp; Temp = "Error changing group and owner of file " + File; Temp += " to " + SNFUserName + ":" + SNFGroupName; Temp += ": "; Temp += strerror(errno); throw runtime_error(Temp); } } OutputVerboseEnd(); } void UtilityConfig::SetMode(std::string &File, mode_t mode) { if (Verbose()) { cout << "Set mode of " << File << " to " << std::oct << mode << "..."; } if (!Explain()) { if (chmod(File.c_str(), mode) != 0) { ostringstream Temp; Temp << "Error changing permissions of file " << File << " to " << mode << ": " << strerror(errno); throw runtime_error(Temp.str()); } } OutputVerboseEnd(); } void UtilityConfig::MkDir(std::string &Dir) { if (Verbose()) { cout << "Create directory " << Dir << "..."; } if (!Explain()) { if (mkdir(Dir.c_str(), 0) != 0) { ostringstream Temp; Temp << "Error creating directory " << Dir << ": " << strerror(errno); throw runtime_error(Temp.str()); } } OutputVerboseEnd(); } void UtilityConfig::StartOrRestartMta(std::string Mta) { if (Verbose()) { cout << "Restarting the " << Mta << " MTA..."; } if (!Explain()) { cout << "restarting the MTA is not implemented..."; } OutputVerboseEnd(); } bool UtilityConfig::CheckForString(std::string Line, std::string SearchString) { string::size_type Indx; Indx = Line.find_first_not_of(" \t"); // Trim leading whitespace. if (string::npos != Indx) { Line = Line.substr(Indx); } if (Line.substr(0, SearchString.length()) == SearchString) { return true; } return false; } void UtilityConfig::LoadInfo(){ if ("OpenBSD" == OperatingSystemType) { OsSpec = OpenBSD; PostfixMainCfPath = "/usr/local/etc/postfix/main.cf"; PostfixMasterCfPath = "/usr/local/etc/postfix/master.cf"; } else if ("FreeBSD" == OperatingSystemType) { OsSpec = FreeBSD; PostfixMainCfPath = "/etc/postfix/main.cf"; PostfixMasterCfPath = "/etc/postfix/master.cf"; } else if ("Ubuntu" == OperatingSystemType) { OsSpec = Ubuntu; PostfixMainCfPath = "/etc/postfix/main.cf"; PostfixMasterCfPath = "/etc/postfix/master.cf"; } else if ("RedHat" == OperatingSystemType) { OsSpec = RedHat; PostfixMainCfPath = "/etc/postfix/main.cf"; PostfixMasterCfPath = "/etc/postfix/master.cf"; } else if ("Suse" == OperatingSystemType) { OsSpec = Suse; PostfixMainCfPath = "/etc/postfix/main.cf"; PostfixMasterCfPath = "/etc/postfix/master.cf"; } else { ostringstream Temp; Temp << "Internal error in UtilityConfig::GetOsSpec: Invalid value of OperatingSystemType: " << OperatingSystemType; throw runtime_error(Temp.str()); } } void UtilityConfig::UpdateIgnoreListFile() { string IgnoreListPath = GetWorkspacePath(); string IgnoreListFile; IgnoreListFile = IgnoreListPath + DirectorySeparator; IgnoreListFile += "GBUdbIgnoreList.txt"; if (!FileExists(IgnoreListFile)) { Copy(SampleIgnoreListFile, IgnoreListFile); // Use SNFMilter.xml.sample. } SetMode(IgnoreListFile, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); // Set permissions. SetOwnerGroup(IgnoreListFile); // Set to sniffer user. } void UtilityConfig::UpdateLogDir() { string LogDir = GetLogPath(); if (!FileExists(LogDir)) { MkDir(LogDir); } SetMode(LogDir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); SetOwnerGroup(LogDir); } bool UtilityConfig::ProcessCommandLineItem(std::string OneInput) { bool ValidCommand = false; if (OneInput == VerboseKey) { VerboseRequested = true; ValidCommand = true; } else if (OneInput == ExplainKey) { ExplainRequested = true; ValidCommand = true; } else if (OneInput == HelpKey) { HelpRequested = true; ValidCommand = true; } return ValidCommand; } bool UtilityConfig::Verbose() { return (VerboseRequested || ExplainRequested); } bool UtilityConfig::Explain() { return ExplainRequested; } bool UtilityConfig::Help() { return HelpRequested; } std::string UtilityConfig::HelpCommandLine() { std::string Help; Help = "[ " + VerboseKey + " | " + ExplainKey + " ]"; return Help; } std::string UtilityConfig::HelpDescription() { std::string Desc; Desc = " -v Provide verbose output\n"; Desc += " -explain Provide an explaination of the actions\n"; Desc += " without executing any commands\n"; return Desc; } void UtilityConfig::OutputVerboseEnd() { if (Verbose() && !Explain()) { cout << "done.\n"; } else if (Explain()) { cout << "\n"; } }