// 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 OS-dependent constants. #ifdef WIN // Windows OS. const std::string UtilityConfig::SampleIgnoreListFile("C:\\SNF\\GBUdbIgnoreList.txt.sample"); const std::string UtilityConfig::RulebaseDownloadCommand("FIX THIS"); const std::string UtilityConfig::RulebaseDownloadStatusFile("FIX THIS"); const std::string ScriptNameKey("FIX THIS"); ///< Text to replace with script name. const std::string SnifferPathKey("FIX THIS"); ///< Text to replace with directory of the rulebase. const std::string UtilityConfig::SampleRulebaseScriptFile("C:\\SNF\\getRulebase.sample"); const std::string UtilityConfig::OperatingSystemType("Windows"); #else // *nix OS. // SCRIPT is replaced with the full path of the script run, // SNIFFER_PATH is replaced with the path of the rulebase. const std::string UtilityConfig::RulebaseDownloadCommand ("(cd SNIFFER_PATH; touch UpdateReady.txt; chown snfuser UpdateReady.txt; su -m snfuser -c SCRIPT)"); const std::string ScriptNameKey("SCRIPT"); ///< Text to replace with script name. const std::string SnifferPathKey("SNIFFER_PATH"); ///< Text to replace with directory of the rulebase. // SNIFFER_PATH is replaced with the path of the rulebase. const std::string UtilityConfig::RulebaseDownloadStatusFile("SNIFFER_PATH/getRulebase.status"); #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 #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 #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 /// Verbose command-line input. const string VerboseKey("-v"); /// Explain command-line input. const string ExplainKey("-explain"); /// Help command-line input. const string HelpKey("-h"); /// Setup command-line input. const string SetupKey("-setup"); /// Repair command-line input. const string RepairKey("-repair"); /// Start sniffer command-line input. const string StartSnifferKey("-start"); /// Stop sniffer command-line input. const string StopSnifferKey("-stop"); /// Configuration file command-line input. const string ConfigFileKey("-config="); /// License ID command-line input. const string LicenseIdKey("-id="); /// Authentication command-line input. const string AuthenticationKey("-auth="); /// String that indicates a successful rulebase download. // // This string must be in the last line of the getRulebase status // file. Note: The getRulebase status file is created by the // getRulebase script, has the name getRulebase.status, and is in the // same directory as the rulebase files. const string SuccessKey("Success"); const string LicenseSearchString = "LICENSE_ID="; const string AuthSearchString = "AUTHENTICATION="; const string IdentityElementName = "identity"; const string LicenseAttributeName = "licenseid"; const string AuthenticationAttributeName = "authentication"; ////////////////////////////////////////////////////////////////////////////////////////////////////////// // End of configuration. ///////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// UtilityConfig::UtilityConfig() : LicenseIdIsSpecified(false), AuthenticationIsSpecified(false) { SetExplain(false); SetVerbose(false); SetHelp(false); SetSetupRepair(false); SetStartSniffer(false); SetStopSniffer(false); } void UtilityConfig::CheckAndSetConfigFileName(const std::string DefaultFile[], int NumDefaultFiles) { string ProvisionalConfigFile = ConfigFileName; 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. if (NumDefaultFiles > 0) { ProvisionalConfigFile = DefaultFile[0]; // Use the first default file. } else { // No default config file was specified. ostringstream Temp; Temp << "Internal error: NumDefaultFiles <= 0 at " << __FILE__ << ":" << __LINE__; throw runtime_error(Temp.str()); } } else if (FoundFile.size() > 1) { // Multiple default files 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); } } SetConfigFileName(ProvisionalConfigFile); } void UtilityConfig::CreateDefaultConfigFile(std::string SampleConfigFile) { std::string File = GetConfigFileName(); if (!FileExists(File)) { if (!Explain()) { SaveFile.CreateBackupFile(File); } // Create the config file. Copy(SampleConfigFile, File); } SetMode(File, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); // Set permissions. SetOwnerGroup(File); // Set to sniffer user. } void UtilityConfig::LoadConfig() { if (Verbose()) { cout << "Using configuration file " << GetConfigFileName() << ".\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 ConfigFileName; } void UtilityConfig::SetConfigFileName(string Name) { ConfigFileName = 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; } string UtilityConfig::GetIgnoreListFileName(void) { return GetWorkspacePath() + "GBUdbIgnoreList.txt"; } string UtilityConfig::GetRulebaseFileName(void) { std::string Name; Name = GetRulebasePath(); Name += LicenseId + ".snf"; return Name; } string UtilityConfig::GetOperatingSystemType(void) { return OperatingSystemType; } void UtilityConfig::LoadInfo(){ if ("OpenBSD" == OperatingSystemType) { PostfixMainCfPath = "/usr/local/etc/postfix/main.cf"; PostfixMasterCfPath = "/usr/local/etc/postfix/master.cf"; SnifferStartScriptDir = "/usr/local/sbin/"; } else if ("FreeBSD" == OperatingSystemType) { PostfixMainCfPath = "/etc/postfix/main.cf"; PostfixMasterCfPath = "/etc/postfix/master.cf"; SnifferStartScriptDir = "/usr/local/etc/rc.d/"; } else if ("Ubuntu" == OperatingSystemType) { PostfixMainCfPath = "/etc/postfix/main.cf"; PostfixMasterCfPath = "/etc/postfix/master.cf"; SnifferStartScriptDir = "/etc/init.d/"; } else if ("RedHat" == OperatingSystemType) { PostfixMainCfPath = "/etc/postfix/main.cf"; PostfixMasterCfPath = "/etc/postfix/master.cf"; SnifferStartScriptDir = "/etc/init.d/"; } else if ("Suse" == OperatingSystemType) { PostfixMainCfPath = "/etc/postfix/main.cf"; PostfixMasterCfPath = "/etc/postfix/master.cf"; SnifferStartScriptDir = "/etc/init.d/"; } else { ostringstream Temp; Temp << "Internal error in UtilityConfig::LoadInfo: Invalid value of OperatingSystemType: " << OperatingSystemType; throw runtime_error(Temp.str()); } } void UtilityConfig::SetupRepairIdentityFile(std::string SampleIdentityFile) { std::string File = GetIdentityFileName(); if (!FileExists(File)) { if (!Explain()) { SaveFile.CreateBackupFile(File); } // Create the config file. Copy(SampleIdentityFile, File); } } void UtilityConfig::SetupRepairRulebaseScript() { std::string File = GetRulebaseScriptName(); if (!FileExists(File)) { if (!Explain()) { SaveFile.CreateBackupFile(File); } Copy(SampleRulebaseScriptFile, File); // Copy if !Explain(). } SetMode(File, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); // Set permissions. } void UtilityConfig::SetupRepairIgnoreListFile() { string File = GetIgnoreListFileName(); if (!FileExists(File)) { if (!Explain()) { SaveFile.CreateBackupFile(File); } Copy(SampleIgnoreListFile, File); } SetMode(File, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); // Set permissions. SetOwnerGroup(File); // Set to sniffer user. } void UtilityConfig::SetupRepairLogDir() { 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); } void UtilityConfig::SetupRepair(const std::string SampleIdentityFile) { SetupRepairIdentityFile(SampleIdentityFile); SetupRepairRulebaseScript(); SetupRepairIgnoreListFile(); SetupRepairLogDir(); } void UtilityConfig::UpdateRulebaseScriptCredentials() { std::string File = GetRulebaseScriptName(); if (Verbose()) { cout << "Update authentication and license ID in the rulebase download script file " << File << "--\n"; } ifstream Input; Input.open(File.c_str()); // Read the contents. if (!Input) { string Temp; Temp = "Error opening rulebase download script file " + File; Temp += " for reading: "; Temp += strerror(errno); throw runtime_error(Temp); } string Content; string Line; bool FoundLicense = false; bool FoundAuth = false; while (getline(Input, Line)) { if (CheckForString(Line, LicenseSearchString)) { // Check for license line. if (FoundLicense) { // Second license line found? string Temp; Temp = "Rulebase sownload script file " + File; Temp += " has the wrong format: Found two lines beginning with " + LicenseSearchString; throw runtime_error(Temp); } if (Verbose()) { cout << " Modify line: '" << Line << "'...\n"; } FoundLicense = true; Line = LicenseSearchString + LicenseId; // Add license line. Line += " # Added by SNFSetup"; } if (CheckForString(Line, AuthSearchString)) { // Check for authentication line. if (FoundAuth) { // Second authentication line found? string Temp; Temp = "Rulebase download script file " + File; Temp += " has the wrong format: Found two lines beginning with " + AuthSearchString; throw runtime_error(Temp); } if (Verbose()) { cout << " Modify line: '" << Line << "'...\n"; } FoundAuth = true; Line = AuthSearchString + Authentication; // Add authentication line. Line += " # Added by SNFSetup"; } Content += Line + "\n"; } if (!FoundLicense || !FoundAuth) { string Temp; Temp = "Rulebase download script file " + File; Temp += " has the wrong format: Missing required line beginning with '" + LicenseSearchString; Temp += "' or '" + AuthSearchString; Temp += "'"; throw runtime_error(Temp); } if (!Input.eof()) { // Should be at end-of-file. string Temp; Temp = "Error reading the rulebase download script file " + File; Temp += ": "; Temp += strerror(errno); throw runtime_error(Temp); } Input.close(); if (Input.bad()) { string Temp; Temp = "Error closing the rulebase download script file " + File; Temp += " after reading: "; Temp += strerror(errno); throw runtime_error(Temp); } if (!Explain()) { SaveFile.CreateBackupFile(File); ofstream Output; // Write the updated contents. Output.open(File.c_str(), ios::trunc); if (!Output) { string Temp; Temp = "Error opening rulebase download script file " + File; Temp += " for writing: "; Temp += strerror(errno); throw runtime_error(Temp); } Output << Content; if (!Output) { string Temp; Temp = "Error writing the rulebase download script file " + File; Temp += ": "; Temp += strerror(errno); throw runtime_error(Temp); } Output.close(); if (!Output) { string Temp; Temp = "Error closing the rulebase download script file " + File; Temp += " after writing: "; Temp += strerror(errno); throw runtime_error(Temp); } } OutputVerboseEnd(); } void UtilityConfig::DownloadRulebase() { if (Verbose()) { std::cout << "Downloading the rulebase..."; std::cout.flush(); } std::string Command; Command = RulebaseDownloadCommand; std::string::size_type ScriptIndex = Command.find(ScriptNameKey); if (ScriptIndex != std::string::npos) { // Insert script full path? Command.replace(ScriptIndex, ScriptNameKey.length(), GetRulebaseScriptName()); } std::string::size_type SnifferPathIndex = Command.find(SnifferPathKey); if (SnifferPathIndex != std::string::npos) { // Insert rulebase location? Command.replace(SnifferPathIndex, SnifferPathKey.length(), GetRulebasePath()); } std::string StatusFile; // Construct download status file name. StatusFile = RulebaseDownloadStatusFile; SnifferPathIndex = StatusFile.find(SnifferPathKey); if (SnifferPathIndex != std::string::npos) { // Insert rulebase location? StatusFile.replace(SnifferPathIndex, SnifferPathKey.length(), GetRulebasePath()); } if (!Explain()) { SaveFile.CreateBackupFile(GetRulebaseFileName()); // Save the current rulebase file. if (0 != remove(StatusFile.c_str())) { // Delete the status file. if (ENOENT != errno) { // No error if the file doesn't exist. std::ostringstream Temp; Temp << "Unable to remove rulebase download status file " << StatusFile << ": " << strerror(errno) << "\n"; throw runtime_error(Temp.str()); } } if (std::system(Command.c_str()) != 0) { // Download the rulebase. string Temp; Temp = "Error running the command '" + Command; Temp += "'."; throw runtime_error(Temp); } ifstream Input; Input.open(StatusFile.c_str()); // Check the status. if (!Input) { string Temp; Temp = "Error opening rulebase download scriptstatus file " + StatusFile; Temp += ": "; Temp += strerror(errno); throw runtime_error(Temp); } string Line; string PrevLine; string Content; while (getline(Input, Line)) { // Read the last line. PrevLine = Line; Content += Line + "\n"; } if (PrevLine.find(SuccessKey) == std::string::npos) { // Check the status. string Temp; Temp = "Error downloading the rulebase. Rulebase download status:\n\n" + Content; throw runtime_error(Temp); } } OutputVerboseEnd(); } void UtilityConfig::UpdateIdentityFile() { std::string File = GetIdentityFileName(); if (Verbose()) { cout << "Update authentication and license ID in the identity file " << File << "--\n"; } ifstream Input; Input.open(File.c_str()); // Read the contents. if (!Input) { string Temp; Temp = "Error opening identity file " + File; Temp += " for reading: "; Temp += strerror(errno); throw runtime_error(Temp); } ostringstream InputContents; if (!Input.eof()) { // Copy if there are characters. // Copying an empty file causes InputContents << Input.rdbuf(); // failbit to be set. } if (InputContents.bad() || InputContents.fail()) { std::string Temp; Temp = "Error reading identity file " + File; throw std::runtime_error(Temp); } Input.close(); if (Input.bad()) { string Temp; Temp = "Error closing the identity file " + File; Temp += " after reading: "; Temp += strerror(errno); throw runtime_error(Temp); } string Content = InputContents.str(); try { ReplaceXmlAttribute(&Content, IdentityElementName, LicenseAttributeName, LicenseId); ReplaceXmlAttribute(&Content, IdentityElementName, AuthenticationAttributeName, Authentication); } catch (std::exception &e) { std::string Temp; Temp = "Error updating credentials for identity file " + File; Temp += ": "; Temp += e.what(); throw runtime_error(Temp); } if (!Explain()) { SaveFile.CreateBackupFile(File); ofstream Output; Output.open(File.c_str(), ios::trunc); if (!Output) { string Temp; Temp = "Error opening identity file " + File; Temp += " for writing: "; Temp += strerror(errno); throw runtime_error(Temp); } Output << Content; if (!Output) { string Temp; Temp = "Error writing the identity file " + File; Temp += ": "; Temp += strerror(errno); throw runtime_error(Temp); } Output.close(); if (!Output) { string Temp; Temp = "Error closing the identity file " + File; Temp += " after writing: "; Temp += strerror(errno); throw runtime_error(Temp); } } OutputVerboseEnd(); } #if 0 void UtilityConfig::UpdateIdentityFileOld() { std::string File = GetIdentityFileName(); ofstream Output; if (Verbose()) { cout << "Create identity file " << File << "..."; } if (!Explain()) { SaveFile.CreateBackupFile(File); Output.open(File.c_str()); if (!Output) { string Temp; Temp = "Error opening identity file " + File; Temp += ": "; Temp += strerror(errno); throw runtime_error(Temp); } Output << "\n" << "\n" << " \n" << "\n"; if (!Output) { string Temp; Temp = "Error writing identity file " + File; Temp += ": "; Temp += strerror(errno); throw runtime_error(Temp); } Output.close(); if (!Output) { string Temp; Temp = "Error closing identity file " + File; Temp += ": "; Temp += strerror(errno); throw runtime_error(Temp); } } OutputVerboseEnd(); SetOwnerGroup(File); // Set the user and group. SetMode(File, S_IRUSR); // Set to readonly by owner. } #endif void UtilityConfig::StartSniffer(std::string Script) { std::string Command; Command = SnifferStartScriptDir + Script; Command += " start"; if (Verbose()) { cout << "Starting Sniffer with the command '" << Command << "'..."; } if (!Explain()) { if (std::system(Command.c_str()) == -1) { // Start the sniffer. string Temp; Temp = "Error running the command '" + Command; Temp += "' to start the Sniffer: "; Temp += strerror(errno); throw runtime_error(Temp); } } OutputVerboseEnd(); } bool UtilityConfig::ProcessCommandLineItem(std::string OneInput) { bool ValidCommand = true; std::string TempString; if (OneInput == VerboseKey) { SetVerbose(true); } else if (OneInput == ExplainKey) { SetExplain(true); } else if (OneInput == HelpKey) { SetHelp(true); } else if (OneInput == SetupKey) { SetSetupRepair(true); } else if (OneInput == RepairKey) { SetSetupRepair(true); } else if (OneInput == StartSnifferKey) { SetStartSniffer(true); } else if (OneInput == StopSnifferKey) { SetStopSniffer(true); } else if (OneInput == ConfigFileKey) { SetConfigFileName(OneInput.substr(ConfigFileKey.length())); } else if (0 == OneInput.find(LicenseIdKey)) { TempString = Trim(OneInput.substr(LicenseIdKey.length())); // Copy only if not null after trimming. if (!TempString.empty()) { LicenseId = TempString; LicenseIdIsSpecified = true; } else { ValidCommand = false; } } else if (0 == OneInput.find(AuthenticationKey)) { Authentication = Trim(OneInput.substr(AuthenticationKey.length())); AuthenticationIsSpecified = true; } else { ValidCommand = false; } return ValidCommand; } bool UtilityConfig::CommandLineIsOkay() { return (AuthenticationIsSpecified == LicenseIdIsSpecified); } std::string UtilityConfig::HelpCommandLine(std::string ExclusiveCommandsHelp) { std::string Help; Help = SetupKey + " | "; Help += RepairKey + " | "; Help += ExclusiveCommandsHelp + " | "; Help += LicenseIdKey + "licenseid " + AuthenticationKey + "authentication | "; Help += StartSnifferKey + " | "; Help += StopSnifferKey + " "; Help += "[" + ConfigFileKey + "snf-config-file] "; Help += "[ " + VerboseKey + " " + ExplainKey + " ]"; return Help; } std::string UtilityConfig::HelpDescription(std::string ExclusiveCommandsHelp) { std::string Desc; Desc = "creates and updates the configuration files (snf-config-file and\n"; Desc += "the ignore list file), the rulebase download script (default: getRulebase),\n"; Desc += "and the identity file if they don't exist.\n\n"; Desc += " -setup Perform initial setup/replace missing files\n"; Desc += " -repair Perform initial setup/replace missing files\n"; Desc += ExclusiveCommandsHelp; Desc += " -id=licenseid Specifies the license ID\n"; Desc += " -auth=authentication Specifies the Authentication\n"; Desc += " -start Start the sniffer\n"; Desc += " -stop Stop the sniffer\n"; Desc += " -config=snf-config-file Specifies the configuration file\n"; 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::SetSetupRepair(bool Specified) { SetupRepairRequested = Specified; } bool UtilityConfig::SetupRepairSpecified() { return SetupRepairRequested; } bool UtilityConfig::UpdateCredentialsSpecified() { return ( (LicenseId.length() > 0) && (Authentication.length() > 0) ); } void UtilityConfig::SetStartSniffer(bool Specified) { StartSnifferRequested = Specified; } bool UtilityConfig::StartSnifferSpecified() { return StartSnifferRequested; } void UtilityConfig::SetStopSniffer(bool Specified) { StopSnifferRequested = Specified; } bool UtilityConfig::StopSnifferSpecified() { return StopSnifferRequested; }