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
## 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 *~ |
// 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"; | |||||
} | |||||
} |
// 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 |
## 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) |
// 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. | |||||
} |
// \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 |
// 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. | |||||
} |
## 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) |
// /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"; | |||||
} |
// \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 |
// 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. | |||||
} |