integrating/unintegrating with postfix), but backup/restore of configuration files is not implemented. Also, SNFIdentity does not download a new rulebase. git-svn-id: https://svn.microneil.com/svn/SNFUtility/trunk@2 aa37657e-1934-4a5f-aa6d-2d8eab27ff7cmaster
@@ -0,0 +1,29 @@ | |||
## Process this file with automake to produce Makefile.in | |||
## | |||
## $Id$ | |||
## | |||
## | |||
## Author: Alban Deniz | |||
## | |||
## Copyright (C) 2011 by MicroNeil Corporation. All rights reserved. | |||
## | |||
CXXFLAGS = $(SNF_CXXFLAGS) -I@top_srcdir@/SNFMulti \ | |||
-DSNF_OSTYPE=\"$(SNF_OSTYPE)\" -DDEFAULT_DATA_DIR=\"@datadir@/$(PACKAGE_NAME)\" \ | |||
-DSBIN_DIR=\"$(DESTDIR)$(sbindir)\" | |||
noinst_LIBRARIES = \ | |||
libUtilityCommon.a | |||
libUtilityCommon_a_SOURCES = \ | |||
@top_srcdir@/SNFUtility/Common/UtilityConfig.cpp | |||
noinst_HEADERS = \ | |||
@top_srcdir@/SNFUtility/Common/UtilityConfig.hpp | |||
EXTRA_DIST = \ | |||
Makefile.am \ | |||
ChangeLog | |||
clean-local: | |||
rm -f *.gcno *.gcov *.gcda *~ |
@@ -0,0 +1,710 @@ | |||
// 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 <cerrno> | |||
#include <cstring> | |||
#include <unistd.h> | |||
#include <pwd.h> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <stdexcept> | |||
#include <sstream> | |||
#include <iostream> | |||
#include <fstream> | |||
#include <vector> | |||
#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<string> 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"; | |||
} | |||
} |
@@ -0,0 +1,305 @@ | |||
// UtilityConfig.hpp | |||
// | |||
// Copyright (C) 2011 ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file defines the interface used by the configuration utilities. | |||
// | |||
#ifndef UtilityConfighpp_included | |||
#define UtilityConfighpp_included | |||
#include "SNFMulti.hpp" | |||
#include <string> | |||
/// Base class for the Sniffer configuration. | |||
// | |||
// This class provides capability common to the configuration applications. | |||
// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
class UtilityConfig { | |||
public: | |||
/// Default constructor. | |||
UtilityConfig(); | |||
/// Check whether a file exists. | |||
// | |||
// \returns true if the file exists, false otherwise. | |||
// | |||
bool FileExists(std::string File); | |||
/// Load the specified or default config file. | |||
// | |||
// This function loads (or reloads) the config file specified in | |||
// the most recent call to LoadConfigFile. If LoadConfigFile has | |||
// not been called, then this method searches for a unique default | |||
// config file in the specified list, and loads that config file. | |||
// | |||
// \param[in] DefaultFile is the list of default locations of the file. | |||
// | |||
// \param[in] NumDefaultFiles is the number of defaultlocations. | |||
// | |||
// If the local data member ConfigFile has a value of "" on input, | |||
// then this function checks for the existence (but not | |||
// readability) of a configuration file in several locations. If | |||
// exactly one file exists, then that file is loaded and | |||
// ConfigFile is set to that name. Otherwise, an exception is | |||
// thrown. | |||
// | |||
void CheckAndLoadConfigFile(const std::string DefaultFile[], int NumDefaultFiles); | |||
/// Load the specified configuration file. | |||
// | |||
// \param[in] Name is the name of the configuration file. | |||
// | |||
void LoadConfigFile(std::string Name); | |||
/// Set the configuration file name. | |||
// | |||
// \param[in] Name is the name of the configuration file. | |||
// | |||
void SetConfigFileName(std::string Name); | |||
/// Get the configuration file name. | |||
// | |||
// \returns the name of the configuration file. | |||
// | |||
std::string GetConfigFileName(void); | |||
/// Get the contents of the <platform> element of the loaded | |||
/// config file. | |||
// | |||
// \returns the contents of the <platform> element. | |||
// | |||
string GetPlatformContents(void); | |||
/// Get the workspace path. | |||
// | |||
// \returns the workspace path. | |||
std::string GetWorkspacePath(void); | |||
/// Get the rulebase path. | |||
// | |||
// \returns the rulebase path. | |||
std::string GetRulebasePath(void); | |||
/// Get the log path. | |||
// | |||
// \returns the log path. | |||
std::string GetLogPath(void); | |||
/// Get the identity file name. | |||
// | |||
// \returns the identity file name. | |||
std::string GetIdentityFileName(void); | |||
/// Get the rulebase script file name. | |||
// | |||
// \returns the rulebase script file name. | |||
std::string GetRulebaseScriptName(void); | |||
/// Copy a file. | |||
// | |||
// \param[in] From is the name of the source file. | |||
// | |||
// \param[in] To is the name of the destination file. | |||
// | |||
void Copy(std::string From, std::string To); | |||
/// Set the owner and group of the specified file. | |||
// | |||
// This function sets the owner and group of the specified file to the | |||
// value specified in UtilityConfig.cpp. | |||
// | |||
// \param[in] File is the specified file. | |||
// | |||
// \see SNFUserName. | |||
// | |||
// \see SNFGroupName. | |||
// | |||
void SetOwnerGroup(std::string &File); | |||
/// Set the mode of a file. | |||
// | |||
// This function sets the mode of the specified file. If an error | |||
// occurs, an exception is thrown. | |||
// | |||
// \param[in] File is the specified file. | |||
// | |||
// \param[in] is the mode. | |||
// | |||
void SetMode(std::string &File, mode_t mode); | |||
/// Create a directory. | |||
// | |||
// This function creates the specified directory. If an error | |||
// occurs, an exception is thrown. | |||
// | |||
// \param[in] Dir is the directory to create. | |||
// | |||
void MkDir(std::string &Dir); | |||
/// Create a backup link of the specified file. | |||
// | |||
// This method creates a backup of the specified file by creating | |||
// a link to the file. The name of the link is the name of the | |||
// file appended by the BackupSuffix data member. | |||
// | |||
// The file can be restored from the backup link by | |||
// RestoreFromBackupLink. | |||
// | |||
// \param[in] File is the file name to create a backup link for. | |||
// | |||
// \throws std::runtime_error in case of error. | |||
// | |||
// \see RestoreFromBackupLink. | |||
// | |||
void CreateBackupLink(std::string File); | |||
/// Remove the backup link of the specified file. | |||
// | |||
// This method removes the backup link of the specified file by | |||
// creating a link to the file. The name of the link is the name | |||
// of the file appended by the BackupSuffix data member. | |||
// | |||
// \param[in] File is the file name whose backup link is to be | |||
// removed. | |||
// | |||
void RemoveBackupLink(std::string File); | |||
/// Restore the specified file from the backup link. | |||
// | |||
// This method restores the specified from the backup link created | |||
// by CreateBackupLink(). | |||
// | |||
// \param[in] File is the file name whose backup link is to be | |||
// removed. | |||
// | |||
// \see CreateBackupLink. | |||
// | |||
void RestoreFromBackupLink(std::string File); | |||
/// Restart the MTA. | |||
// | |||
// This function starts or restarts the MTA. | |||
// | |||
// \param[in] Mta specifies the MTA. The acceptable values are | |||
// "postfix" and "sendmail". | |||
// | |||
void StartOrRestartMta(std::string Mta); | |||
/// Check for a specified string at the beginning of a line. | |||
// | |||
// This function checks for the specified string at the beginning of a | |||
// line. Leading whitespace in the line is ignored. | |||
// | |||
// \param[in] Line is the line. | |||
// | |||
// \param[in] SearchString is the string to check for. | |||
// | |||
static bool CheckForString(std::string Line, std::string SearchString); | |||
/// Operating system specification. | |||
enum OperatingSystemSpecEnum { | |||
OpenBSD, ///< OpenBSD OS. | |||
FreeBSD, ///< FreeBSD OS. | |||
Ubuntu, ///< Ubuntu and variants. | |||
RedHat, ///< RedHat and variants. | |||
Suse ///< Suse and variants. | |||
}; | |||
/// Load the operating-system-dependent info (file locations, etc). | |||
// | |||
// This method updates the public members that contain the OS | |||
// specification and file paths. | |||
// | |||
void LoadInfo(); | |||
/// OS specification. | |||
OperatingSystemSpecEnum OsSpec; | |||
/// Postfix main.cf file path. | |||
std::string PostfixMainCfPath; | |||
/// Postfix main.cf file path. | |||
std::string PostfixMasterCfPath; | |||
/// Create or update the ignore list file. | |||
// | |||
// The ignore list file is created if it dosn't exist. In any | |||
// case, the owner/group is changed by SetOwnerGroup(), and the | |||
// permissions are changed to readonly for everyone, and | |||
// read/write for the owner. | |||
void UpdateIgnoreListFile(); | |||
/// Create or update the log directory. | |||
// | |||
// The log directory is created if it dosn't exist. In any case, | |||
// the owner/group is changed by SetOwnerGroup(), and the | |||
// permissions are changed to r-x for everyone, and rwx for the | |||
// owner. | |||
void UpdateLogDir(); | |||
/// Process one command-line item. | |||
// | |||
// \param[in] OneInput is the command-line item to process. | |||
// | |||
bool ProcessCommandLineItem(std::string OneInput); | |||
/// Provide verbose output? | |||
// | |||
// \returns true if the application is to provide verbose output. | |||
// | |||
bool Verbose(); | |||
/// Provide an explanation of the actions only? | |||
// | |||
// \returns true if the application is to provide an explanation | |||
// of the actions without executing any commands. | |||
// | |||
bool Explain(); | |||
/// Provide help? | |||
// | |||
// \returns true if the application is to output a help message. | |||
// | |||
bool Help(); | |||
/// Output the legal command-line input. | |||
std::string HelpCommandLine(); | |||
/// Output the description of the legal command-line input. | |||
std::string HelpDescription(); | |||
/// Output the end of a verbose output line. | |||
void OutputVerboseEnd(); | |||
private: | |||
bool VerboseRequested; ///< User requested verbose processing. | |||
bool ExplainRequested; ///< User requested verbose processing but without actually executing the commands. | |||
bool HelpRequested; ///< User requested help. | |||
std::string ConfigFile; ///< Configuration file name. | |||
static const std::string SampleIgnoreListFile; ///< Sample ignore list file. | |||
static const std::string SampleRulebaseScriptFile; ///< Sample rulebase script file. | |||
static const std::string BackupSuffix; ///< Suffix appended to create backup file name. | |||
snfCFGData CFGData; ///< Configuration data. | |||
/// Operating system type. | |||
// | |||
// This is either Windows or the value specified for | |||
// --enable-os-type when configuring for *nix. | |||
static const std::string OperatingSystemType; | |||
}; | |||
#endif |
@@ -0,0 +1,41 @@ | |||
## Process this file with automake to produce Makefile.in | |||
## | |||
## $Id$ | |||
## | |||
## automake input for the MicroNeil SNFMilter application (SNFMilter directory). | |||
## | |||
## Author: Alban Deniz | |||
## | |||
## Copyright (C) 2011 ARM Research Labs, LLC. | |||
## See www.armresearch.com for the copyright terms. | |||
## | |||
## | |||
LIBS = @SNF_LIBS@ -L../../SNFMulti -L../../CodeDweller -L../Common -lUtilityCommon \ | |||
-lSNFMulti -lCodeDweller @LIBS@ | |||
CXXFLAGS = $(SNF_CXXFLAGS) -I@top_srcdir@/SNFMulti -I@top_srcdir@/CodeDweller \ | |||
-I@top_srcdir@/SNFUtility/Common | |||
sbin_PROGRAMS = \ | |||
SNFIdentity | |||
SNFIdentity_SOURCES = \ | |||
@top_srcdir@/SNFUtility/SNFIdentity/main.cpp \ | |||
@top_srcdir@/SNFUtility/SNFIdentity/SNFIdentityConfig.cpp | |||
noinst_HEADERS = \ | |||
@top_srcdir@/SNFUtility/SNFIdentity/SNFIdentityConfig.hpp | |||
EXTRA_DIST = \ | |||
Makefile.am \ | |||
ChangeLog | |||
install-exec-hook: | |||
ln -f $(DESTDIR)$(sbindir)/SNFIdentity$(EXEEXT) $(DESTDIR)$(sbindir)/SNFDebugIdentity$(EXEEXT) | |||
uninstall-hook: | |||
rm -f $(DESTDIR)$(sbindir)/SNFDebugIdentity$(EXEEXT) | |||
clean-local: | |||
rm -f *.gcno *.gcov *.gcda *~ $(CONFDATA) |
@@ -0,0 +1,317 @@ | |||
// SNFIdentity.cpp | |||
// | |||
// Copyright (C) 2011, ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file contains the functions for SNFIdentityConfig. | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#include <errno.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
#include <pwd.h> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <unistd.h> | |||
#include <exception> | |||
#include <stdexcept> | |||
#include <sstream> | |||
#include <iostream> | |||
#include <fstream> | |||
#include <vector> | |||
#include "SNFIdentityConfig.hpp" | |||
using namespace std; | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
const string LicenseSearchString = "LICENSE_ID="; | |||
const string AuthSearchString = "AUTHENTICATION="; | |||
const string ConfigFileKey("-config="); | |||
const string LicenseIdKey("-id="); | |||
const string AuthenticationKey("-auth="); | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
void | |||
SNFIdentityConfig::DisplayHelp(std::string Version, const std::string DefaultConfigFile[], int NumDefaultConfigFiles) { | |||
cout | |||
<< Version << endl | |||
<< "Copyright (C) 2011, ARM Research Labs, LLC (www.armresearch.com)\n\n" | |||
<< "Usage:\n\n" | |||
<< "SNFIdentity [" << ConfigFileKey << "snf-config-file] " << LicenseIdKey << "licenseid " | |||
<< AuthenticationKey << "authentication " | |||
<< UtilityConfig::HelpCommandLine() << "\n\n" | |||
<< " -config=snf-config-file Specifies the configuration file\n" | |||
<< " -id=licenseid Specifies the license ID\n" | |||
<< " -auth=authentication Specifies the Authentication\n" | |||
<< UtilityConfig::HelpDescription() << "\n" | |||
<< "If snf-config-file is not specified, then the following files are tried:\n\n"; | |||
for (int i = 0; i < NumDefaultConfigFiles; i++) { | |||
cout << " " << DefaultConfigFile[i] + "\n"; | |||
} | |||
cout << "\nIf more than one default file is found, then SNFIdentity aborts.\n"; | |||
}; | |||
bool | |||
SNFIdentityConfig::GetCommandLineInput(int argc, char* argv[]) { | |||
int i; | |||
string OneInput; | |||
for (i = 1; i < argc; i++) { // Check each input. | |||
OneInput = argv[i]; | |||
if (0 == OneInput.find(ConfigFileKey)) { | |||
SetConfigFileName(OneInput.substr(ConfigFileKey.length())); | |||
} else if (0 == OneInput.find(LicenseIdKey)) { | |||
LicenseID = OneInput.substr(LicenseIdKey.length()); | |||
} else if (0 == OneInput.find(AuthenticationKey)) { | |||
Authentication = OneInput.substr(AuthenticationKey.length()); | |||
} else { | |||
// Process command-line input by the base class. | |||
if (!ProcessCommandLineItem(OneInput)) { | |||
return false; // Illegal input. | |||
} | |||
} | |||
} | |||
return ( (LicenseID.length() > 0) && | |||
(Authentication.length() > 0)); | |||
} | |||
void | |||
SNFIdentityConfig::CreateIdentityFile() { | |||
ofstream Output; | |||
std::string File = GetIdentityFileName(); | |||
if (Verbose()) { | |||
cout << "Create identity file " << File << "..."; | |||
} | |||
if (!Explain()) { | |||
Output.open(File.c_str()); | |||
if (!Output) { | |||
string Temp; | |||
Temp = "Error opening identity file " + File; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
Output << "<!-- License file created by SNFIdentity-->\n" | |||
<< "<snf>\n" | |||
<< " <identity licenseid='" << LicenseID << "' authentication='" | |||
<< Authentication << "'/>\n" | |||
<< "</snf>\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. | |||
} | |||
void | |||
SNFIdentityConfig::UpdateRulebaseScriptCredentials() { | |||
std::string File = GetRulebaseScriptName(); | |||
if (Verbose()) { | |||
cout << "Update authentication and license ID in the rulebase file " << File << "--\n"; | |||
} | |||
ifstream Input; | |||
Input.open(File.c_str()); // Read the contents. | |||
if (!Input) { | |||
string Temp; | |||
Temp = "Error opening rulebase 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 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 SNFIdentity"; | |||
} | |||
if (CheckForString(Line, AuthSearchString)) { // Check for authentication line. | |||
if (FoundAuth) { // Second authentication line found? | |||
string Temp; | |||
Temp = "Rulebase 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 SNFIdentity"; | |||
} | |||
Content += Line + "\n"; | |||
} | |||
if (!FoundLicense || !FoundAuth) { | |||
string Temp; | |||
Temp = "Rulebase 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 file " + File; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
Input.close(); | |||
if (Input.bad()) { | |||
string Temp; | |||
Temp = "Error closing the rulebase file " + File; | |||
Temp += " after reading: "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
if (!Explain()) { | |||
ofstream Output; // Write the updated contents. | |||
Output.open(File.c_str(), ios::trunc); | |||
if (!Output) { | |||
string Temp; | |||
Temp = "Error opening rulebase file " + File; | |||
Temp += " for writing: "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
Output << Content; | |||
if (!Output) { | |||
string Temp; | |||
Temp = "Error writing the rulebase file " + File; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
Output.close(); | |||
if (!Output) { | |||
string Temp; | |||
Temp = "Error closing the rulebase file " + File; | |||
Temp += " after writing: "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
SetMode(File, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); // Set permissions. | |||
} |
@@ -0,0 +1,81 @@ | |||
// \file SNFIdentityConfig.hpp | |||
// | |||
// Copyright (C) 2011 ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file defines the SNFIdentityConfig interface. | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#ifndef SNFIdentityConfighpp_included | |||
#define SNFIdentityConfighpp_included | |||
#include <string> | |||
#include "UtilityConfig.hpp" | |||
/// Class to manage the sniffer credentials. | |||
// | |||
// This class creates the sniffer identity.xml file, and updates the | |||
// getRulebase script with the specified sniffer credentials. | |||
// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
class SNFIdentityConfig : public UtilityConfig { | |||
public: | |||
/// Structure to hold the command-line parameters. | |||
struct CommandLineInput { | |||
std::string ConfigFile; ///< Configuration file name. | |||
std::string LicenseID; ///< License ID credentials. | |||
std::string Authentication; ///< Authentication credentials. | |||
}; | |||
/// Display usage. | |||
// | |||
// \param[in] Version is the SNFIdentity version. | |||
// | |||
// \param[in] DefaultConfigFile is the list of default locations of the | |||
// configuration file. | |||
// | |||
// \param[in] NumDefaultConfigFiles is the number of default configuration files. | |||
// | |||
void DisplayHelp(std::string Version, const std::string DefaultConfigFile[], int NumDefaultConfigFiles); | |||
/// Get the command-line input parameters for SNFIdentity. | |||
// | |||
// \param[in] argc is the number of parameters. | |||
// | |||
// \param[in] argv is the parameters. | |||
// | |||
// \returns true if all the required command line parameters are | |||
// present and there are no unknown command-line parameters, false | |||
// otherwise. | |||
// | |||
bool GetCommandLineInput(int argc, char* argv[]); | |||
/// Create the identity file. | |||
// | |||
// The file is created, the owner/group is changed by SetOwnerGroup(), | |||
// and the permissions are changed to readonly for the owner. | |||
// | |||
// \see SetOwnerGroup(). | |||
// | |||
void CreateIdentityFile(); | |||
/// Update the rulebase script with the credentials. | |||
// | |||
void UpdateRulebaseScriptCredentials(); | |||
private: | |||
std::string LicenseID; ///< License ID string. | |||
std::string Authentication; ///< Authentication string. | |||
}; | |||
#endif |
@@ -0,0 +1,103 @@ | |||
// main.cpp | |||
// | |||
// Copyright (C) 2011, ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// Configure the identity.xml and getRulebase files with the license | |||
// and authentication credentials. | |||
// | |||
// The license and authentication credentials are specified on the | |||
// command line, and are used to create the identity.xml and update | |||
// the getRulebase files with that information. | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#include <errno.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
#include <pwd.h> | |||
#include <sys/stat.h> | |||
#include <exception> | |||
#include <iostream> | |||
#include <fstream> | |||
#include "SNFMulti.hpp" | |||
#include "SNFIdentityConfig.hpp" | |||
using namespace std; | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
/// Version string. | |||
const char* SNF_IDENTITY_VERSION = "SNFIdentity 0.0.1 Build: " __DATE__ " " __TIME__; | |||
/// Locations to search for default configuration files. | |||
const string DefaultConfigFile[] = { | |||
"/etc/snf-milter/SNFMilter.xml", | |||
"/usr/local/etc/snf-milter/SNFMilter.xml", | |||
"/etc/snf-server/SNFServer.xml", | |||
"/usr/local/etc/snf-server/SNFServer.xml" | |||
}; | |||
const size_t DefaultConfigFileSize = sizeof DefaultConfigFile / sizeof DefaultConfigFile[0]; | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
int main(int argc, char* argv[]) { | |||
SNFIdentityConfig SnfIdentityConfig; | |||
if (!SnfIdentityConfig.GetCommandLineInput(argc, argv) || // If our command line arguments | |||
SnfIdentityConfig.Help()) { // don't look right, or if help is | |||
// requested then display our help | |||
SnfIdentityConfig.DisplayHelp(SNF_IDENTITY_VERSION, // screen. | |||
DefaultConfigFile, | |||
DefaultConfigFileSize); | |||
return 0; | |||
} | |||
bool DebugMode = false; // This will be our debug mode. | |||
string argv0(argv[0]); // Capture how we were called. | |||
if( | |||
string::npos != argv0.find("Debug") || // If we find "Debug" or | |||
string::npos != argv0.find("debug") // "debug" in our command path | |||
) { // then we are in DebugMode. | |||
DebugMode = true; // Set the flag and tell the | |||
cout << SNF_IDENTITY_VERSION << endl; // watchers. | |||
cout << "Debug Mode" << endl; | |||
} | |||
try { // Catch anything that breaks loose. | |||
SnfIdentityConfig.CheckAndLoadConfigFile(DefaultConfigFile, // Load configuration from the | |||
DefaultConfigFileSize); // config file specified on the | |||
// command line, or the default file. | |||
SnfIdentityConfig.CreateIdentityFile(); | |||
SnfIdentityConfig.UpdateRulebaseScriptCredentials(); | |||
} // That's all folks. | |||
catch(exception& e) { // Report any normal exceptions. | |||
cerr << "SNFIdentity Exception: " << e.what() << endl; | |||
} | |||
catch (snfCFGmgr::LoadFailure) { // Error loading configuration file. | |||
cerr << "snfCFGmgr Exception: Unable to load the configuration file " | |||
<< SnfIdentityConfig.GetConfigFileName() << endl; | |||
} | |||
catch(...) { // Report any unexpected exceptions. | |||
cerr << "SNFIdentity Panic! Unknown Exception!" << endl; | |||
} | |||
return 0; // Normally we return zero. | |||
} |
@@ -0,0 +1,41 @@ | |||
## Process this file with automake to produce Makefile.in | |||
## | |||
## $Id$ | |||
## | |||
## automake input for the MicroNeil SNFMilter application (SNFMilter directory). | |||
## | |||
## Author: Alban Deniz | |||
## | |||
## Copyright (C) 2011 ARM Research Labs, LLC. | |||
## See www.armresearch.com for the copyright terms. | |||
## | |||
## | |||
LIBS = @SNF_LIBS@ -L../../SNFMulti -L../../CodeDweller -L../Common -lUtilityCommon \ | |||
-lSNFMulti -lCodeDweller @LIBS@ | |||
CXXFLAGS = $(SNF_CXXFLAGS) -I@top_srcdir@/SNFMulti -I@top_srcdir@/CodeDweller \ | |||
-I@top_srcdir@/SNFUtility/Common -DDEFAULT_CONFIG_DIR=\"@sysconfdir@\" | |||
sbin_PROGRAMS = \ | |||
SNFMilterConfig | |||
SNFMilterConfig_SOURCES = \ | |||
@top_srcdir@/SNFUtility/SNFMilterConfig/main.cpp \ | |||
@top_srcdir@/SNFUtility/SNFMilterConfig/SNFMilterConfig.cpp | |||
noinst_HEADERS = \ | |||
@top_srcdir@/SNFUtility/SNFMilterConfig/SNFMilterConfig.hpp | |||
EXTRA_DIST = \ | |||
Makefile.am \ | |||
ChangeLog | |||
install-exec-hook: | |||
ln -f $(DESTDIR)$(sbindir)/SNFMilterConfig$(EXEEXT) $(DESTDIR)$(sbindir)/SNFDebugMilterConfig$(EXEEXT) | |||
uninstall-hook: | |||
rm -f $(DESTDIR)$(sbindir)/SNFDebugMilterConfig$(EXEEXT) | |||
clean-local: | |||
rm -f *.gcno *.gcov *.gcda *~ $(CONFDATA) |
@@ -0,0 +1,442 @@ | |||
// /file SNFMilterConfig.cpp | |||
// | |||
// Copyright (C) 2011, ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file contains the functions for SNFMilterConfig. | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#include <errno.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
#include <pwd.h> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <unistd.h> | |||
#include <exception> | |||
#include <stdexcept> | |||
#include <sstream> | |||
#include <iostream> | |||
#include <fstream> | |||
#include <vector> | |||
#include "SNFMilterConfig.hpp" | |||
using namespace std; | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Initialize default configuration file path. | |||
#ifdef WIN | |||
// Windows OS. | |||
const std::string SNFMilterConfig::DefaultConfigFile("C:\\SNF\\SNFMilter.xml"); | |||
const std::string SNFMilterConfig::DefaultSampleConfigFile("C:\\SNF\\SNFMilter.xml.sample"); | |||
#else | |||
#ifdef DEFAULT_CONFIG_DIR | |||
// *nix, DEFAULT_CONFIG_DIR is specified on the compile command line. | |||
const std::string SNFMilterConfig::DefaultConfigFile(DEFAULT_CONFIG_DIR "/snf-milter/SNFMilter.xml"); | |||
const std::string SNFMilterConfig::DefaultSampleConfigFile(DEFAULT_CONFIG_DIR "/snf-milter/SNFMilter.xml.sample"); | |||
#else | |||
// Not Windows, and DEFAULT_CONFIG_DIR is not specified on the compile | |||
// command line. In this case, we don't know the default path for the | |||
// configuration file. | |||
const std::string SNFMilterConfig::DefaultConfigFile(""); | |||
const std::string SNFMilterConfig::DefaultSampleConfigFile(""); | |||
#endif | |||
#endif | |||
const string ConfigFileKey("-config="); | |||
const string IntegrateWithNoneKey("-mta=none"); | |||
const string IntegrateWithPostfixKey("-mta=postfix"); | |||
const string IntegrateWithSendmailKey("-mta=sendmail"); | |||
const string SnfMilterMainCfSearchString("Added by SNFMilterConfig"); | |||
const string SnfMilterMainCfIntegrationString("smtpd_milters = unix:/var/snf-milter/socket $smtpd_milters # Added by SNFMilterConfig"); | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
void | |||
SNFMilterConfig::DisplayHelp(std::string Version) { | |||
cout | |||
<< Version << endl | |||
<< "Copyright (C) 2012, ARM Research Labs, LLC (www.armresearch.com)\n\n" | |||
<< "Usage:\n\n" | |||
<< "SNFMilterConfig [" << ConfigFileKey << "snf-config-file] " | |||
<< IntegrateWithPostfixKey << " | " | |||
<< IntegrateWithSendmailKey << " | " | |||
<< IntegrateWithNoneKey << " " | |||
<< UtilityConfig::HelpCommandLine() << "\n\n" | |||
<< "SNFMilterConfig creates the configuration files (snf-config-file and the ignore list file) and the\n" | |||
<< "rulebase download script (default: getRulebase) if they don't exist.\n\n" | |||
<< " -config=snf-config-file Specifies the configuration file\n" | |||
<< " -mta=postfix Integrate with postfix\n" | |||
<< " -mta=sendmail Integrate with sendmail\n" | |||
<< " -mta=none Remove any integration with all supported MTAs\n" | |||
<< UtilityConfig::HelpDescription() << "\n" | |||
<< "If snf-config-file is not specified, then the following file is used:\n\n" | |||
<< " " << DefaultConfigFile << "\n\n"; | |||
}; | |||
bool | |||
SNFMilterConfig::GetCommandLineInput(int argc, char* argv[]) { | |||
int i; | |||
int NumCommandsFound = 0; | |||
string OneInput; | |||
string ConfigFile; | |||
for (i = 1; i < argc; i++) { // Check each input. | |||
OneInput = argv[i]; | |||
if (0 == OneInput.find(ConfigFileKey)) { | |||
ConfigFile = OneInput.substr(ConfigFileKey.length()); | |||
} else if (OneInput == IntegrateWithNoneKey) { | |||
Command = IntegrateWithNoneCmd; | |||
NumCommandsFound++; | |||
} else if (OneInput == IntegrateWithPostfixKey) { | |||
Command = IntegrateWithPostfixCmd; | |||
NumCommandsFound++; | |||
} else if (0 == OneInput.find(IntegrateWithSendmailKey)) { | |||
Command = IntegrateWithSendmailCmd; | |||
NumCommandsFound++; | |||
} else { | |||
// Process command-line input by the base class. | |||
if (!ProcessCommandLineItem(OneInput)) { | |||
return false; // Illegal input. | |||
} | |||
} | |||
} | |||
if (0 == ConfigFile.length()) { // Load default config file name. | |||
ConfigFile = DefaultConfigFile; | |||
} | |||
LoadConfigFile(ConfigFile); | |||
LoadInfo(); // Load the file paths. | |||
LoadSocketInfo(); // Load the socket path. | |||
return (NumCommandsFound == 1); | |||
} | |||
void | |||
SNFMilterConfig::LoadSocketInfo() { | |||
std::string MilterElement = GetPlatformContents(); | |||
ConfigurationData PlatformConfig(MilterElement.c_str(), MilterElement.length()); | |||
ConfigurationElement SocketReader("milter"); | |||
SocketReader | |||
.Element("socket") | |||
.Attribute("path", SocketFileName) | |||
.End("socket") | |||
.End("milter"); | |||
SocketReader.interpret(PlatformConfig); | |||
} | |||
void | |||
SNFMilterConfig::CreateSocketDir() { | |||
std::string SocketDir; | |||
std::string::size_type LastDirSepIndex = SocketFileName.rfind("/"); | |||
SocketDir = ( (std::string::npos == LastDirSepIndex) ? SocketFileName : SocketFileName.substr(0, LastDirSepIndex)); | |||
if (Verbose()) { | |||
cout << "Create the milter socket directory " << SocketDir << "..."; | |||
} | |||
if (!Explain()) { | |||
if (!FileExists(SocketDir)) { | |||
MkDir(SocketDir); | |||
} | |||
SetMode(SocketDir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP); | |||
SetOwnerGroup(SocketDir); | |||
} | |||
OutputVerboseEnd(); | |||
} | |||
void | |||
SNFMilterConfig::UpdateConfigFiles() { | |||
std::string ConfigFileName = GetConfigFileName(); | |||
if (!FileExists(ConfigFileName)) { | |||
Copy(DefaultSampleConfigFile, ConfigFileName); // Use SNFMilter.xml.sample. | |||
} | |||
SetMode(ConfigFileName, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); // Set permissions. | |||
SetOwnerGroup(ConfigFileName); // Set to sniffer user. | |||
UpdateLogDir(); | |||
UpdateIgnoreListFile(); | |||
} | |||
void | |||
SNFMilterConfig::DoIntegrationCommand() { | |||
switch (Command) { | |||
case IntegrateWithNoneCmd: | |||
UnintegrateWithAll(); | |||
break; | |||
case IntegrateWithPostfixCmd: | |||
IntegrateWithPostfix(); | |||
break; | |||
case IntegrateWithSendmailCmd: | |||
IntegrateWithSendmail(); | |||
break; | |||
default: | |||
{ | |||
ostringstream Temp; | |||
Temp << "Internal error in SNFMilterConfig::DoCommand: Invalid value of command: " << Command; | |||
throw runtime_error(Temp.str()); | |||
} | |||
} | |||
} | |||
void | |||
SNFMilterConfig::UnintegrateWithAll() { | |||
UnintegrateWithPostfix(); | |||
UnintegrateWithSendmail(); | |||
// TODO: Restart MTA. | |||
// Do not remove the socket directory; users might have placed | |||
// files in it. This happened with the /tmp directory; it was | |||
// supposed to be only for files that would be deleted on reboot. | |||
// However, admins stored files that they wished to be persistent | |||
// across reboots in /tmp. | |||
} | |||
void | |||
SNFMilterConfig::IntegrateWithPostfix() { | |||
UnintegrateWithAll(); // Remove any existing integration. | |||
if (Verbose()) { | |||
cout << "Add to postfix file " << PostfixMainCfPath << ": '" | |||
<< SnfMilterMainCfIntegrationString << "'..."; | |||
} | |||
if (!Explain()) { | |||
ofstream Output; // Append the configuration. | |||
Output.open(PostfixMainCfPath.c_str(), ios::app); | |||
if (!Output) { | |||
string Temp; | |||
Temp = "Error opening the postfix configuration file " + PostfixMainCfPath; | |||
Temp += " for writing: "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
Output << SnfMilterMainCfIntegrationString << "\n"; | |||
if (!Output) { | |||
string Temp; | |||
Temp = "Error appending to the postfix configuration file " + PostfixMainCfPath; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
Output.close(); | |||
if (!Output) { | |||
string Temp; | |||
Temp = "Error closing the postfix configuration file " + PostfixMainCfPath; | |||
Temp += " after appending: "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
CreateSocketDir(); | |||
StartOrRestartMta("postfix"); | |||
} | |||
void | |||
SNFMilterConfig::UnintegrateWithPostfix() { | |||
ifstream Input; | |||
if (Verbose()) { | |||
cout << "Remove any integration in postfix file " << PostfixMainCfPath << "--\n"; | |||
} | |||
Input.open(PostfixMainCfPath.c_str()); // Read the contents. | |||
if (!Input) { | |||
string Temp; | |||
Temp = "Error opening the postfix configuration file " + PostfixMainCfPath; | |||
Temp += " for reading: "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
string Content; | |||
string Line; | |||
while (getline(Input, Line)) { | |||
if (string::npos != Line.find(SnfMilterMainCfSearchString)) { // Check for integration line. | |||
if (Verbose()) { | |||
cout << " Remove '" << Line << "'...\n"; | |||
} | |||
continue; // Do not copy this line. | |||
} | |||
Content += Line + "\n"; // Copy this line. | |||
} | |||
if (!Input.eof()) { // Should be at end-of-file. | |||
string Temp; | |||
Temp = "Error reading the postfix configuration file " + PostfixMainCfPath; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
Input.close(); | |||
if (Input.bad()) { | |||
string Temp; | |||
Temp = "Error closing the postfix configuration file " + PostfixMainCfPath; | |||
Temp += " after reading: "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
if (!Explain()) { | |||
ofstream Output; // Write the updated contents. | |||
Output.open(PostfixMainCfPath.c_str(), ios::trunc); | |||
if (!Output) { | |||
string Temp; | |||
Temp = "Error opening the postfix configuration file " + PostfixMainCfPath; | |||
Temp += " for writing: "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
Output << Content; | |||
if (!Output) { | |||
string Temp; | |||
Temp = "Error writing the postfix configuration file " + PostfixMainCfPath; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
Output.close(); | |||
if (!Output) { | |||
string Temp; | |||
Temp = "Error closing the postfix configuration file " + PostfixMainCfPath; | |||
Temp += " after writing: "; | |||
Temp += strerror(errno); | |||
throw runtime_error(Temp); | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
} | |||
void | |||
SNFMilterConfig::IntegrateWithSendmail() { | |||
throw runtime_error("Integration with sendmail is not implemented"); | |||
} | |||
void | |||
SNFMilterConfig::UnintegrateWithSendmail() { | |||
std::cerr << "Unintegration with sendmail is not implemented" << "\n"; | |||
} |
@@ -0,0 +1,94 @@ | |||
// \file SNFMilterConfig.hpp | |||
// | |||
// Copyright (C) 2011 ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file defines the SNFMilterConfig interface. | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#ifndef SNFMilterConfighpp_included | |||
#define SNFMilterConfighpp_included | |||
#include <string> | |||
#include "UtilityConfig.hpp" | |||
/// Class to manage the SNFMilter configuration. | |||
// | |||
// This class creates/maintains the sniffer configuration file, and | |||
// integrates/unintegrates with MTAs. | |||
// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
class SNFMilterConfig : public UtilityConfig { | |||
public: | |||
/// Command. | |||
enum CommandEnum { | |||
IntegrateWithNoneCmd, ///< Remove integration with all MTAs. | |||
IntegrateWithPostfixCmd, ///< Integrate with postfix. | |||
IntegrateWithSendmailCmd ///< Integrate with sendmail. | |||
}; | |||
/// Display usage. | |||
// | |||
// \param[in] Version is the SNFMilter version. | |||
// | |||
void DisplayHelp(std::string Version); | |||
/// Get the command-line input parameters for SNFMilter. | |||
// | |||
// \param[in] argc is the number of parameters. | |||
// | |||
// \param[in] argv is the parameters. | |||
// | |||
// \returns true if all the required command line parameters are | |||
// present and there are no unknown command-line parameters, false | |||
// otherwise. | |||
// | |||
bool GetCommandLineInput(int argc, char* argv[]); | |||
/// Create or update the configuration files. | |||
// | |||
// The SNFMilter.xml and GBUdbIgnoreList.txt files are created if | |||
// they don't exist. In any case, the owner/group is changed by | |||
// SetOwnerGroup(), and the permissions are changed to readonly | |||
// for everyone, and read/write for the owner. | |||
// | |||
void UpdateConfigFiles(); | |||
/// Execute the command to integrate/unintegrate with the MTAs. | |||
void DoIntegrationCommand(); | |||
private: | |||
/// Load the socket info (file name) from the <platform> section | |||
/// of the loaded config file. | |||
void LoadSocketInfo(); | |||
void CreateSocketDir(); | |||
void IntegrateWithPostfix(); ///< Integrate with postfix. | |||
void UnintegrateWithPostfix(); ///< Unintegrate with postfix. | |||
void IntegrateWithSendmail(); ///< Integrate with sendmail. | |||
void UnintegrateWithSendmail(); ///< Unintegrate with sendmail. | |||
void UnintegrateWithAll(); ///< Unintegrate with all MTAs. | |||
CommandEnum Command; ///< Specified command. | |||
static const std::string DefaultConfigFile; ///< Default config file. | |||
static const std::string DefaultSampleConfigFile; ///< Sample config file. | |||
std::string SocketFileName; | |||
}; | |||
#endif |
@@ -0,0 +1,88 @@ | |||
// main.cpp | |||
// | |||
// Copyright (C) 2012, ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// Create and maintain the sniffer configuration file for SNFMilter. | |||
// | |||
// The configuration file and instructions are specified on the | |||
// command line, and are used to create/modify the configuration file, | |||
// and integrate or unintegrate with the specified MTA. | |||
// | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#include <errno.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
#include <pwd.h> | |||
#include <sys/stat.h> | |||
#include <exception> | |||
#include <iostream> | |||
#include <fstream> | |||
#include "SNFMulti.hpp" | |||
#include "SNFMilterConfig.hpp" | |||
using namespace std; | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
/// Version string. | |||
const char* SNF_MILTERCONFIG_VERSION = "SNFMilterConfig 0.0.1 Build: " __DATE__ " " __TIME__; | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
int main(int argc, char* argv[]) { | |||
SNFMilterConfig SnfMilterConfig; | |||
if (!SnfMilterConfig.GetCommandLineInput(argc, argv) || // If our command line arguments | |||
SnfMilterConfig.Help()) { // don't look right, or if help is | |||
// requested then display our help | |||
SnfMilterConfig.DisplayHelp(SNF_MILTERCONFIG_VERSION); // screen. | |||
return 0; | |||
} | |||
bool DebugMode = false; // This will be our debug mode. | |||
string argv0(argv[0]); // Capture how we were called. | |||
if( | |||
string::npos != argv0.find("Debug") || // If we find "Debug" or | |||
string::npos != argv0.find("debug") // "debug" in our command path | |||
) { // then we are in DebugMode. | |||
DebugMode = true; // Set the flag and tell the | |||
cout << SNF_MILTERCONFIG_VERSION << endl; // watchers. | |||
cout << "Debug Mode" << endl; | |||
} | |||
try { // Catch anything that breaks loose. | |||
SnfMilterConfig.UpdateConfigFiles(); // Create config files if they don't | |||
// exist, or update config files. | |||
SnfMilterConfig.DoIntegrationCommand(); // Integrate/unintegrate. | |||
} // That's all folks. | |||
catch(exception& e) { // Report any normal exceptions. | |||
cerr << "SNFMilterConfig Exception: " << e.what() << endl; | |||
} | |||
catch (snfCFGmgr::LoadFailure) { // Error loading configuration file. | |||
cerr << "snfCFGmgr Exception: Unable to load the configuration file " | |||
<< SnfMilterConfig.GetConfigFileName() << endl; | |||
} | |||
catch(...) { // Report any unexpected exceptions. | |||
cerr << "SNFMilterConfig Panic! Unknown Exception!" << endl; | |||
} | |||
return 0; // Normally we return zero. | |||
} |