git-svn-id: https://svn.microneil.com/svn/SNFUtility/trunk@63 aa37657e-1934-4a5f-aa6d-2d8eab27ff7cmaster
@@ -0,0 +1,629 @@ | |||
// /file PostfixIntegrate.cpp | |||
// | |||
// Copyright (C) 2013, ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file contains the functions for PostfixIntegrate. | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#include <cstdlib> | |||
#include <cerrno> | |||
#include <cstring> | |||
#include <iostream> | |||
#include <exception> | |||
#include <stdexcept> | |||
#include <sstream> | |||
#include <fstream> | |||
#include "PostfixIntegrate.hpp" | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
void | |||
PostfixIntegrate::SetOperatingSystem(std::string OperatingSystemType) { | |||
MtaIsRunningCommand = "ps axl | grep -v grep | grep -q 'postfix/master'"; | |||
PostfixDefaultIsChrooted = false; // Overwritten if postfix is | |||
SnfSnifferDirName = "/usr/sbin"; // by default chrooted. | |||
SnfSnifferFileName = SnfSnifferDirName + "/snfSniffer"; | |||
SnfSnifferSampleFileName = SnfSnifferFileName + ".sample"; | |||
ContentFilterLine = " -o content_filter=snfilter:dummy\n"; | |||
ContentFilterSpec = "snfilter unix - n n - 10 pipe\n"; | |||
if ("OpenBSD" == OperatingSystemType) { | |||
PostfixDefaultIsChrooted = true; | |||
SnfSnifferDirName = "/usr/local/sbin"; | |||
SnfSnifferFileName = SnfSnifferDirName + "/snfSniffer"; | |||
SnfSnifferSampleFileName = "/usr/local/sbin/snfSniffer.sample"; | |||
ContentFilterSpec += " flags=Rq user=snfuser argv=/usr/local/sbin/snfSniffer\n"; | |||
PostfixMainCfPath = "/etc/postfix/main.cf"; | |||
PostfixMasterCfPath = "/etc/postfix/master.cf"; | |||
ReloadMtaCommand = "/usr/local/sbin/postfix reload"; | |||
} else if ("FreeBSD" == OperatingSystemType) { | |||
ContentFilterSpec += " flags=Rq user=snfuser argv=/usr/local/sbin/snfSniffer\n"; | |||
SnfSnifferDirName = "/usr/local/sbin"; | |||
SnfSnifferFileName = SnfSnifferDirName + "/snfSniffer"; | |||
SnfSnifferSampleFileName = "/usr/local/sbin/snfSniffer.sample"; | |||
PostfixMainCfPath = "/usr/local/etc/postfix/main.cf"; | |||
PostfixMasterCfPath = "/usr/local/etc/postfix/master.cf"; | |||
ReloadMtaCommand = "/usr/local/sbin/postfix reload"; | |||
} else if ("Ubuntu" == OperatingSystemType) { | |||
PostfixDefaultIsChrooted = true; | |||
SnfSnifferFileName = SnfSnifferDirName + "/snfSniffer"; | |||
SnfSnifferSampleFileName = "/usr/sbin/snfSniffer.sample"; | |||
ContentFilterSpec += " flags=Rq user=snfuser argv=/usr/sbin/snfSniffer\n"; | |||
PostfixMainCfPath = "/etc/postfix/main.cf"; | |||
PostfixMasterCfPath = "/etc/postfix/master.cf"; | |||
ReloadMtaCommand = "/usr/sbin/postfix reload"; | |||
} else if ("RedHat" == OperatingSystemType) { | |||
ContentFilterSpec += " flags=Rq user=snfuser argv=/usr/sbin/snfSniffer\n"; | |||
PostfixMainCfPath = "/etc/postfix/main.cf"; | |||
PostfixMasterCfPath = "/etc/postfix/master.cf"; | |||
ReloadMtaCommand = "/usr/sbin/postfix reload"; | |||
} else if ("Suse" == OperatingSystemType) { | |||
ContentFilterSpec += " flags=Rq user=snfuser argv=/usr/sbin/snfSniffer\n"; | |||
PostfixMainCfPath = "/etc/postfix/main.cf"; | |||
PostfixMasterCfPath = "/etc/postfix/master.cf"; | |||
ReloadMtaCommand = "/usr/sbin/postfix reload"; | |||
} else if ("ArchLinux" == OperatingSystemType) { | |||
ContentFilterSpec += " flags=Rq user=snfuser argv=/usr/sbin/snfSniffer\n"; | |||
PostfixMainCfPath = "/etc/postfix/main.cf"; | |||
PostfixMasterCfPath = "/etc/postfix/master.cf"; | |||
ReloadMtaCommand = "/usr/sbin/postfix reload"; | |||
} else { | |||
std::ostringstream Temp; | |||
Temp << "***Error from PostfixIntegrate::SetOperatingSystem: Invalid value of OperatingSystemType: " | |||
<< OperatingSystemType; | |||
throw std::runtime_error(Temp.str()); | |||
} | |||
ContentFilterSpec += " -f ${sender} -- ${recipient}\n"; | |||
} | |||
void | |||
PostfixIntegrate::Integrate(FileBackup *SaveFile) { | |||
if (IsIntegrated()) { | |||
return; | |||
} | |||
// Check whether the chroot configuration is as expected. | |||
bool IsChrooted; | |||
IsChrooted = MtaConfigurationIsChrooted(); | |||
if (IsChrooted != PostfixDefaultIsChrooted) { | |||
std::string Temp; | |||
Temp = "Error--postfix must be configured to run "; | |||
Temp += (PostfixDefaultIsChrooted ? "" : "not "); | |||
Temp += "chrooted, which is the default for this operating system. "; | |||
Temp += "postfix was detected to be configured to run "; | |||
Temp += (IsChrooted ? "" : "not "); | |||
Temp += "chrooted."; | |||
throw std::runtime_error(Temp); | |||
} | |||
if (Verbose()) { | |||
std::cout << "Integrate with postfix...\n"; | |||
} | |||
std::string Content; | |||
if (!Explain()) { | |||
if (!FileExists(SnfSnifferFileName)) { // Create SnfSniffer script | |||
// if it doesn't exist. | |||
SaveFile->CreateBackupFile(SnfSnifferFileName); | |||
if (!FileExists(SnfSnifferDirName)) { | |||
MkDir(SnfSnifferDirName); | |||
} | |||
SetMode(SnfSnifferDirName, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); | |||
SetOwnerGroup(SnfSnifferDirName); | |||
Copy(SnfSnifferSampleFileName, SnfSnifferFileName); | |||
SetMode(SnfSnifferFileName, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); | |||
SetOwnerGroup(SnfSnifferFileName); | |||
} | |||
SaveFile->CreateBackupFile(PostfixMasterCfPath); | |||
std::ifstream Input; | |||
Input.open(PostfixMasterCfPath.c_str()); // Read the contents. | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error opening the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += " for reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
std::string Line; | |||
while (getline(Input, Line)) { | |||
Content += Line + "\n"; // Copy this line. | |||
if ( (Line.find("smtp") == 0) && (Line.find("inet") != std::string::npos) ) { | |||
if (Verbose()) { | |||
std::cout << " Add\n\n " | |||
<< ContentFilterLine | |||
<< "\n\n after\n\n" | |||
<< Line | |||
<< "\n\n in " | |||
<< PostfixMasterCfPath << "...\n"; | |||
} | |||
Content += ContentFilterLine; | |||
} | |||
} | |||
if (!Input.eof()) { // Should be at end-of-file. | |||
std::string Temp; | |||
Temp = "Error reading the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
Input.close(); | |||
if (Input.bad()) { | |||
std::string Temp; | |||
Temp = "Error closing the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += " after reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
if (Verbose()) { | |||
std::cout << " Add\n\n" << ContentFilterSpec << "\n\n to the end of " | |||
<< PostfixMasterCfPath << "...\n"; | |||
} | |||
Content += ContentFilterSpec; | |||
if (!Explain()) { | |||
std::ofstream Output; // Write the updated contents. | |||
Output.open(PostfixMasterCfPath.c_str(), std::ios::trunc); | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error opening the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += " for writing: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
Output << Content; | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error writing the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
Output.close(); | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error closing the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += " after writing: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
if (!ReloadMta()) { | |||
std::cerr << "Unable to reload the postfix configuration. Please run " | |||
<< "'postfix reload' for the integration with SNFServer to take effect."; | |||
} | |||
} | |||
void | |||
PostfixIntegrate::Unintegrate(FileBackup *SaveFile) { | |||
if (!IsIntegrated()) { | |||
return; | |||
} | |||
std::ifstream Input; | |||
if (Verbose()) { | |||
std::cout << "Remove integration in postfix file " << PostfixMasterCfPath << "--\n"; | |||
} | |||
if (!Explain()) { | |||
SaveFile->CreateBackupFile(PostfixMasterCfPath); // Save any existing file. | |||
Input.open(PostfixMasterCfPath.c_str()); // Read the contents. | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error opening the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += " for reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
std::ostringstream ContentStream; | |||
ContentStream << Input.rdbuf(); | |||
Input.close(); | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error closing the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
std::string Content; | |||
Content = ContentStream.str(); | |||
if (Verbose()) { | |||
std::cout << " Remove all occurances of\n\n" << ContentFilterLine << "\n\n" | |||
<< " from" << PostfixMasterCfPath << "...\n"; | |||
} | |||
std::string::size_type IntegrationBegin = std::string::npos; | |||
while ((IntegrationBegin = Content.find(ContentFilterLine)) != std::string::npos) { | |||
Content.erase(IntegrationBegin, ContentFilterLine.length()); | |||
} | |||
if (Verbose()) { | |||
std::cout << " Remove all occurances of\n\n" << ContentFilterSpec << "\n\n" | |||
<< " from" << PostfixMasterCfPath << "...\n"; | |||
} | |||
IntegrationBegin = std::string::npos; | |||
while ((IntegrationBegin = Content.find(ContentFilterSpec)) != std::string::npos) { | |||
Content.erase(IntegrationBegin, ContentFilterSpec.length()); | |||
} | |||
std::ofstream Output; // Write the updated contents. | |||
Output.open(PostfixMasterCfPath.c_str(), std::ios::trunc); | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error opening the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += " for writing: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
Output << Content; | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error writing the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
Output.close(); | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error closing the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += " after writing: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
if (!ReloadMta()) { | |||
std::cerr << "Unable to reload the postfix configuration. Please run " | |||
<< "'postfix reload' for the integration with SNFServer to take effect."; | |||
} | |||
} | |||
bool | |||
PostfixIntegrate::MtaIsRunningDetected() { | |||
if (Verbose()) { | |||
std::cout << "Checking whether postfix is detected to be running..."; | |||
} | |||
bool IsRunningDetected; | |||
IsRunningDetected = (std::system(MtaIsRunningCommand.c_str()) == 0); | |||
if (Verbose()) { | |||
std::cout << (IsRunningDetected ? "yes..." : "no..."); | |||
} | |||
OutputVerboseEnd(); | |||
return IsRunningDetected; | |||
} | |||
bool | |||
PostfixIntegrate::ReloadMta() { | |||
if (!MtaIsRunningDetected()) { | |||
return true; | |||
} | |||
if (Verbose()) { | |||
std::cout << "Reloading postfix...\n"; | |||
std::cout.flush(); | |||
} | |||
bool Succeeded; | |||
if (!Explain()) { | |||
Succeeded = (std::system(ReloadMtaCommand.c_str()) == 0); | |||
if (Verbose()) { | |||
std::cout << (Succeeded ? "succeeded..." : "failed..."); | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
return Succeeded; | |||
} | |||
bool | |||
PostfixIntegrate::IsIntegrated() { | |||
if (Verbose()) { | |||
std::cout << "Checking for any SNFServer integration in the postfix file " << PostfixMasterCfPath << "..."; | |||
} | |||
if (!FileExists(PostfixMasterCfPath)) { | |||
if (Verbose()) { | |||
std::cout << "file doesn't exist; postfix is not integrated..."; | |||
} | |||
OutputVerboseEnd(); | |||
return false; | |||
} | |||
std::ifstream Input; | |||
Input.open(PostfixMasterCfPath.c_str()); // Read the contents. | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error opening the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += " for reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
std::ostringstream ContentStream; | |||
ContentStream << Input.rdbuf(); | |||
Input.close(); | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error closing the postfix configuration file " + PostfixMasterCfPath; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
std::string Content; | |||
Content = ContentStream.str(); | |||
bool FoundContentFilterLine = (Content.find(ContentFilterLine) != std::string::npos); | |||
bool FoundContentFilterSpec = (Content.find(ContentFilterSpec) != std::string::npos); | |||
bool Integrated = (FoundContentFilterLine || FoundContentFilterSpec); | |||
if (Verbose()) { | |||
if (FoundContentFilterLine) { | |||
std::cout << "found\n\n" << ContentFilterLine << "\n\n"; | |||
} | |||
if (FoundContentFilterSpec) { | |||
std::cout << "found\n\n" << ContentFilterSpec << "\n\n"; | |||
} | |||
if (!Integrated) { | |||
std::cout << "none found..."; | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
return Integrated; | |||
} | |||
bool | |||
PostfixIntegrate::DefaultIsChrooted() { | |||
return PostfixDefaultIsChrooted; | |||
} | |||
bool | |||
PostfixIntegrate::MtaConfigurationIsChrooted() { | |||
std::string File; | |||
std::ifstream Input; | |||
File = PostfixMasterCfPath; | |||
Input.open(File.c_str()); | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error opening postfix configuration file " + File; | |||
Temp += " for reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
std::string Line; | |||
bool ConfigurationIsChrooted = false; | |||
while (getline(Input, Line)) { | |||
if (CheckForString(Line, "smtp")) { // Check for smtp line. | |||
std::istringstream Buffer(Line); // Parse buffer line. | |||
std::string Token[8]; | |||
for (unsigned int iToken = 0; iToken < 8; iToken++) { | |||
Buffer >> Token[iToken]; | |||
} | |||
if ( ("y" == Token[4]) || ("-" == Token[4]) ) { | |||
ConfigurationIsChrooted = true; | |||
break; | |||
} | |||
} | |||
} | |||
Input.close(); | |||
if (Input.bad()) { | |||
std::string Temp; | |||
Temp = "Error closing the postfix configuration file " + File; | |||
Temp += " after reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
return ConfigurationIsChrooted; | |||
} |
@@ -0,0 +1,88 @@ | |||
// \file PostfixIntegrate.hpp | |||
// | |||
// Copyright (C) 2012 ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file defines the PostfixIntegrate interface. | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#ifndef PostfixIntegratehpp_included | |||
#define PostfixIntegratehpp_included | |||
#include "MtaIntegrate.hpp" | |||
/// Class to manage the SNFServer integration with postfix. | |||
// | |||
// This class implements the MtaIntegrate interface for postfix. | |||
// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
class PostfixIntegrate : public MtaIntegrate { | |||
public: | |||
virtual void SetOperatingSystem(std::string OperatingSystemType); | |||
virtual void Integrate(FileBackup *SaveFile); | |||
virtual void Unintegrate(FileBackup *SaveFile); | |||
// Return the default chroot configuration of Postfix. | |||
// | |||
// \returns true if the default configuration is for postfix to | |||
// run chrooted, false otherwise. | |||
// | |||
bool DefaultIsChrooted(); | |||
private: | |||
virtual bool MtaIsRunningDetected(); | |||
virtual bool ReloadMta(); | |||
virtual bool IsIntegrated(); | |||
bool MtaConfigurationIsChrooted(); | |||
/// Directory containing the snfSniffer script. | |||
std::string SnfSnifferDirName; | |||
/// snfSniffer script file name, including the directory. | |||
std::string SnfSnifferFileName; | |||
/// Sample snfSniffer script file name, including the directory. | |||
std::string SnfSnifferSampleFileName; | |||
/// Content filter line. | |||
// | |||
// To integrate, this line is added to master.cf just after the | |||
// "smtp" line. | |||
// | |||
std::string ContentFilterLine; | |||
/// Content filter specification. | |||
// | |||
// To integrate this is added to the end of the master.cf line. | |||
// | |||
std::string ContentFilterSpec; | |||
/// Postfix main.cf file path. | |||
std::string PostfixMainCfPath; | |||
/// Postfix master.cf file path. | |||
std::string PostfixMasterCfPath; | |||
/// Command to determine whether postfix is running. | |||
std::string MtaIsRunningCommand; | |||
/// Command to reload postfix. | |||
std::string ReloadMtaCommand; | |||
/// True if postfix runs chrooted by default. | |||
bool PostfixDefaultIsChrooted; | |||
}; | |||
#endif |
@@ -0,0 +1,313 @@ | |||
// /file SNFServerConfig.cpp | |||
// | |||
// Copyright (C) 2011, ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file contains the functions for SNFServerConfig. | |||
// | |||
// $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 "SNFServerConfig.hpp" | |||
using namespace std; | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Initialize default configuration file path. | |||
#ifdef WIN | |||
// Windows OS. | |||
const std::string SNFServerConfig::DefaultConfigFile("C:\\SNF\\SNFServer.xml"); | |||
const std::string SNFServerConfig::SampleConfigFile("C:\\SNF\\SNFServer.xml.sample"); | |||
const std::string SNFServerConfig::SampleIdentityFile("C:\\SNF\\identity.xml.sample"); | |||
const std::string InstallFile(""); | |||
#else | |||
#ifdef DEFAULT_CONFIG_DIR | |||
// *nix, DEFAULT_CONFIG_DIR is specified on the compile command line. | |||
const std::string SNFServerConfig::DefaultConfigFile(DEFAULT_CONFIG_DIR "/snf-server/SNFServer.xml"); | |||
const std::string SNFServerConfig::SampleConfigFile(DEFAULT_CONFIG_DIR "/snf-server/SNFServer.xml.sample"); | |||
const std::string SNFServerConfig::SampleIdentityFile(DEFAULT_CONFIG_DIR "/snf-server/identity.xml.sample"); | |||
const std::string InstallFile(DOC_DIR "/INSTALL"); | |||
#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 SNFServerConfig::DefaultConfigFile(""); | |||
const std::string SNFServerConfig::SampleConfigFile(""); | |||
const std::string SNFServerConfig::SampleIdentityFile(""); | |||
const std::string InstallFile("INSTALL"); | |||
#endif | |||
#endif | |||
const string SNFServerConfig::ApplicationName("SNFServer"); | |||
const string IntegrateWithNoneKey("-with=none"); | |||
const string IntegrateWithPostfixKey("-with=postfix"); | |||
const string IntegrateWithSendmailKey("-with=sendmail"); | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
void | |||
SNFServerConfig::DisplayHelp(std::string Version) { | |||
std::string ExclusiveCommands; | |||
std::string ExclusiveCommandsHelp; | |||
ExclusiveCommands = IntegrateWithPostfixKey + " | "; | |||
ExclusiveCommands += IntegrateWithSendmailKey + " | "; | |||
ExclusiveCommands += IntegrateWithNoneKey; | |||
ExclusiveCommandsHelp = " -with=postfix Integrate with postfix and start/reload postfix\n"; | |||
ExclusiveCommandsHelp += " -with=sendmail Integrate with sendmail and start/reload sendmail\n"; | |||
ExclusiveCommandsHelp += " (Not available on OpenBSD or FreeBSD)\n"; | |||
ExclusiveCommandsHelp += " -with=none Remove any integration with all supported MTAs\n"; | |||
cout | |||
<< Version << endl | |||
<< "Copyright (C) 2012, ARM Research Labs, LLC (www.armresearch.com)\n\n" | |||
<< "Usage:\n\n" | |||
<< "SNFServerConfig " | |||
<< UtilityConfig::HelpCommandLine(ExclusiveCommands) << "\n\n" | |||
<< "SNFServerConfig " | |||
<< UtilityConfig::HelpDescription(ExclusiveCommandsHelp) << "\n" | |||
<< "The configuration file name is:\n\n" | |||
<< " " << DefaultConfigFile << "\n\n" | |||
<< "If the above file doesn't exist, then it is copied from the following file:\n\n" | |||
<< " " << SampleConfigFile << "\n\n" | |||
<< "If integration with an MTA is specified, the MTA's configuration is reloaded " | |||
<< "if the MTA is running.\n\n"; | |||
}; | |||
bool | |||
SNFServerConfig::GetCommandLineInput(int argc, char* argv[]) { | |||
int i; | |||
int NumCommandsFound = 0; | |||
string OneInput; | |||
Command = NoCommand; // Default is to do nothing. | |||
for (i = 1; i < argc; i++) { // Check each input. | |||
OneInput = argv[i]; | |||
if (OneInput == IntegrateWithPostfixKey) { | |||
Command = IntegrateWithPostfixCommand; | |||
NumCommandsFound++; | |||
} else if (0 == OneInput.find(IntegrateWithSendmailKey)) { | |||
std::string OsType; | |||
OsType = GetOperatingSystemType(); // Check whether the platform is supported. | |||
if ( ("OpenBSD" == OsType) || ("FreeBSD" == OsType) ) { | |||
std::string Temp; | |||
Temp = "Integration with sendmail is not supported on " + OsType; | |||
Temp += ".\n"; | |||
Temp += "Please see " + InstallFile; | |||
Temp += " for information on integration with sendmail.\n"; | |||
throw std::runtime_error(Temp); | |||
} | |||
Command = IntegrateWithSendmailCommand; | |||
NumCommandsFound++; | |||
} else if (OneInput == IntegrateWithNoneKey) { | |||
Command = IntegrateWithNoneCommand; | |||
NumCommandsFound++; | |||
} else { | |||
// Process command-line input by the base class. | |||
if (!ProcessCommandLineItem(OneInput)) { | |||
Command = UnknownCommand; | |||
return false; // Illegal input. | |||
} | |||
} | |||
} | |||
if (UpdateCredentialsSpecified()) { | |||
Command = UpdateCredentialsCommand; | |||
NumCommandsFound++; | |||
} | |||
if (SetupRepairSpecified()) { | |||
Command = SetupRepairCommand; | |||
NumCommandsFound++; | |||
} | |||
if (StartSnifferSpecified()) { | |||
Command = StartSnifferCommand; | |||
NumCommandsFound++; | |||
} | |||
if (StopSnifferSpecified()) { | |||
Command = StopSnifferCommand; | |||
NumCommandsFound++; | |||
} | |||
return ( (NumCommandsFound == 1) && CommandLineIsOkay() ); | |||
} | |||
void | |||
SNFServerConfig::ExecuteCommand() { | |||
Postfix.SetOperatingSystem(GetOperatingSystemType()); | |||
Postfix.SetVerbose(Verbose()); | |||
Postfix.SetExplain(Explain()); | |||
Sendmail.SetOperatingSystem(GetOperatingSystemType()); | |||
Sendmail.SetVerbose(Verbose()); | |||
Sendmail.SetExplain(Explain()); | |||
SetConfigFileName(DefaultConfigFile); | |||
if (SetupRepairCommand == Command) { | |||
CreateDefaultConfigFile(SampleConfigFile); // Create the file if it doesn't exist, | |||
// Set owner and mode in any case. | |||
} | |||
LoadConfig(); | |||
LoadInfo(); // Load the file paths. | |||
switch (Command) { | |||
case SetupRepairCommand: | |||
SetupRepair(SampleIdentityFile); | |||
break; | |||
case UpdateCredentialsCommand: | |||
UpdateRulebaseScriptCredentials(); | |||
DownloadRulebase(); | |||
UpdateIdentityFile(); | |||
break; | |||
case IntegrateWithPostfixCommand: | |||
Postfix.Integrate(&SaveFile); | |||
UnintegrateWithAllExcept("postfix"); | |||
break; | |||
case IntegrateWithSendmailCommand: | |||
Sendmail.Integrate(&SaveFile); | |||
UnintegrateWithAllExcept("sendmail"); | |||
break; | |||
case IntegrateWithNoneCommand: | |||
UnintegrateWithAllExcept(); | |||
break; | |||
case StartSnifferCommand: | |||
LoadCredentials(); | |||
StartSniffer("snf-server start", ApplicationName); | |||
break; | |||
case StopSnifferCommand: | |||
LoadCredentials(); | |||
StopSniffer("snf-server stop", ApplicationName); | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
void | |||
SNFServerConfig::SaveFileState() { | |||
if (!Explain()) { | |||
SaveFile.CreateBackupFile(GetRulebaseScriptName()); | |||
if (UpdateCredentialsSpecified()) { | |||
SaveFile.CreateBackupFile(GetRulebaseFileName()); | |||
} | |||
SaveFile.CreateBackupFile(GetIdentityFileName()); | |||
SaveFile.CreateBackupFile(GetIgnoreListFileName()); | |||
} | |||
} | |||
void | |||
SNFServerConfig::UnintegrateWithAllExcept(std::string Except) { | |||
if (Except != "postfix") { | |||
Postfix.Unintegrate(&SaveFile); | |||
} | |||
if (Except != "sendmail") { | |||
Sendmail.Unintegrate(&SaveFile); | |||
} | |||
} |
@@ -0,0 +1,107 @@ | |||
// \file SNFServerConfig.hpp | |||
// | |||
// Copyright (C) 2012 ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file defines the SNFServerConfig interface. | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#ifndef SNFServerConfighpp_included | |||
#define SNFServerConfighpp_included | |||
#include <string> | |||
#include "UtilityConfig.hpp" | |||
#include "PostfixIntegrate.hpp" | |||
#include "SendmailIntegrate.hpp" | |||
/// Class to manage the SNFServer configuration. | |||
// | |||
// This class creates/maintains the sniffer configuration file, and | |||
// integrates/unintegrates with MTAs. | |||
// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
class SNFServerConfig : public UtilityConfig { | |||
public: | |||
/// Command specified. | |||
enum CommandEnum { | |||
SetupRepairCommand, ///< Setup or repair the configuration. | |||
UpdateCredentialsCommand, ///< Update the credentials. | |||
IntegrateWithPostfixCommand, ///< Integrate with postfix. | |||
IntegrateWithSendmailCommand, ///< Integrate with sendmail. | |||
IntegrateWithNoneCommand, ///< Unintegrate with all supported MTAs. | |||
StartSnifferCommand, ///< Start the Sniffer. | |||
StopSnifferCommand, ///< Stop the Sniffer. | |||
NoCommand, ///< No command specified. | |||
UnknownCommand ///< Unknown. | |||
}; | |||
/// Display usage. | |||
// | |||
// \param[in] Version is the SNFServer version. | |||
// | |||
void DisplayHelp(std::string Version); | |||
/// Get the command-line input parameters for SNFServer. | |||
// | |||
// \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[]); | |||
/// Execute the command specified by the command-line parameters. | |||
// | |||
void ExecuteCommand(void); | |||
/// Save the state of all files that might be changed, except the | |||
/// config file. | |||
// | |||
void SaveFileState(void); // OBSOLETE. | |||
private: | |||
PostfixIntegrate Postfix; ///< Postfix integration object. | |||
SendmailIntegrate Sendmail; ///< Sendmail integration object. | |||
/// Unintegrate with MTAs. | |||
// | |||
// Unintegrate with all MTAs except the specified MTA. | |||
// | |||
// \param[in] Except is the MTA to not integrate with. The | |||
// acceptable values are: | |||
// | |||
// <ol> | |||
// <li> "postfix" </li> | |||
// <li> "sendmail" </li> | |||
// <li> "" </li> | |||
// </ol> | |||
// | |||
// The default value is "", which specifies unintegration with all | |||
// MTAs. | |||
// | |||
void UnintegrateWithAllExcept(std::string Except = ""); | |||
CommandEnum Command; ///< Specified command. | |||
static const std::string DefaultConfigFile; ///< Default config file. | |||
static const std::string SampleConfigFile; ///< Sample config file. | |||
static const std::string SampleIdentityFile; ///< Sample identity file. | |||
static const std::string ApplicationName; ///< Application name. | |||
}; | |||
#endif |
@@ -0,0 +1,631 @@ | |||
// /file SendmailIntegrate.cpp | |||
// | |||
// Copyright (C) 2013, ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file contains the functions for SendmailIntegrate. | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#include <cstdlib> | |||
#include <cerrno> | |||
#include <cstring> | |||
#include <iostream> | |||
#include <exception> | |||
#include <stdexcept> | |||
#include <sstream> | |||
#include <fstream> | |||
#include "SendmailIntegrate.hpp" | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
const std::string SendmailLdaKey("FEATURE(`local_procmail'"); ///< Line in sendmail.cf that specifies the LDA. | |||
const std::string MtaIsRunningCommand("ps axl | grep -v grep | grep -q ' sendmail: '"); | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
void | |||
SendmailIntegrate::SetOperatingSystem(std::string OperatingSystemType) { | |||
ProcmailRcFileName = "/etc/procmailrc"; | |||
if ("OpenBSD" == OperatingSystemType) { | |||
IntegrationIsSupported = false; | |||
} else if ("FreeBSD" == OperatingSystemType) { | |||
IntegrationIsSupported = false; | |||
} else if ("Ubuntu" == OperatingSystemType) { | |||
IntegrationIsSupported = true; | |||
SendmailSendmailMcPath = "/etc/mail/sendmail.mc"; | |||
SendmailSendmailCfPath = "/etc/mail/sendmail.cf"; | |||
SnfSnifferDirName = "/var/spool/postfix/snf-server"; | |||
SnfSnifferFileName = SnfSnifferDirName + "/snfSnifferFilter"; | |||
SnfSnifferSampleFileName = "/usr/sbin/snfSnifferFilter.sample"; | |||
BuildInstallSendmailCfFile = "(cd /etc/mail && make)"; | |||
ReloadMtaCommand = "/etc/init.d/sendmail reload"; | |||
FileToBackup.push_back(SendmailSendmailMcPath); | |||
FileToBackup.push_back(SendmailSendmailCfPath); | |||
} else if ("RedHat" == OperatingSystemType) { | |||
IntegrationIsSupported = true; | |||
SendmailSendmailMcPath = "/etc/mail/sendmail.mc"; | |||
SendmailSendmailCfPath = "/etc/mail/sendmail.cf"; | |||
SnfSnifferDirName = "/usr/sbin"; | |||
SnfSnifferFileName = SnfSnifferDirName + "/snfSnifferFilter"; | |||
SnfSnifferSampleFileName = SnfSnifferDirName + "/snfSnifferFilter.sample"; | |||
BuildInstallSendmailCfFile = "(cd /etc/mail && make)"; | |||
ReloadMtaCommand = "/etc/init.d/sendmail reload"; | |||
FileToBackup.push_back(SendmailSendmailMcPath); | |||
FileToBackup.push_back(SendmailSendmailCfPath); | |||
} else if ("Suse" == OperatingSystemType) { | |||
IntegrationIsSupported = true; | |||
SendmailSendmailMcPath = "/etc/mail/linux.mc"; | |||
SendmailSendmailCfPath = "/etc/mail/sendmail.cf"; | |||
SnfSnifferDirName = "/usr/sbin"; | |||
SnfSnifferFileName = SnfSnifferDirName + "/snfSnifferFilter"; | |||
SnfSnifferSampleFileName = SnfSnifferDirName + "/snfSnifferFilter.sample"; | |||
BuildInstallSendmailCfFile = "(cd /etc/mail && rm -f sendmail.cf && m4 /etc/mail/linux.mc > sendmail.cf)"; | |||
ReloadMtaCommand = "/etc/init.d/sendmail reload"; | |||
FileToBackup.push_back(SendmailSendmailMcPath); | |||
FileToBackup.push_back(SendmailSendmailCfPath); | |||
} else { | |||
std::ostringstream Temp; | |||
Temp << "***Error from SendmailIntegrate::SetOperatingSystem: Invalid value of OperatingSystemType: " | |||
<< OperatingSystemType; | |||
throw std::runtime_error(Temp.str()); | |||
} | |||
ProcmailRcSnifferIntegration = ":0 fw\n| " + SnfSnifferFileName; | |||
ProcmailRcSnifferIntegration += "\n"; | |||
} | |||
void | |||
SendmailIntegrate::Integrate(FileBackup *SaveFile) { | |||
if (!IntegrationIsSupported) { | |||
std::ostringstream Temp; | |||
Temp << "Integration with sendmail is not supported on this platform. " | |||
<< "Please see " << DOC_DIR << "/INSTALL for instructions for manual " | |||
<< "integration with sendmail."; | |||
throw std::runtime_error(Temp.str()); | |||
} | |||
if (IsIntegrated()) { | |||
return; | |||
} | |||
// Check whether the configuration has procmail as the LDA. | |||
if (!MtaConfigurationHasProcmailForLda()) { | |||
std::string Temp; | |||
Temp = "Error--sendmail must be configured to use procmail as the LDA."; | |||
throw std::runtime_error(Temp); | |||
} | |||
if (Verbose()) { | |||
std::cout << "Create " << SnfSnifferFileName << " if it doesn't exist..."; | |||
} | |||
if (!Explain()) { | |||
if (!FileExists(SnfSnifferFileName)) { // Create SnfSnifferFilter script | |||
// if it doesn't exist. | |||
SaveFile->CreateBackupFile(SnfSnifferFileName); | |||
if (!FileExists(SnfSnifferDirName)) { | |||
MkDir(SnfSnifferDirName); | |||
} | |||
SetMode(SnfSnifferDirName, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); | |||
SetOwnerGroup(SnfSnifferDirName); | |||
Copy(SnfSnifferSampleFileName, SnfSnifferFileName); | |||
SetMode(SnfSnifferFileName, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); | |||
SetOwnerGroup(SnfSnifferFileName); | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
if (Verbose()) { | |||
std::cout << "Add\n\n" << ProcmailRcSnifferIntegration << "\n\nto " << ProcmailRcFileName << "..."; | |||
} | |||
std::string ProcmailRcFileContent; | |||
if (!Explain()) { | |||
if (FileExists(ProcmailRcFileName)) { // Read any existing procmail configuration. | |||
std::ifstream Input; | |||
Input.open(ProcmailRcFileName.c_str()); | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error opening the procmail configuration file " + ProcmailRcFileName; | |||
Temp += " for reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
if (!Input.eof()) { | |||
std::ostringstream Buffer; | |||
Buffer << Input.rdbuf(); | |||
ProcmailRcFileContent = Buffer.str(); | |||
} | |||
Input.close(); | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error closing the procmail configuration file " + ProcmailRcFileName; | |||
Temp += " after reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
} | |||
ProcmailRcFileContent = ProcmailRcSnifferIntegration + ProcmailRcFileContent; | |||
SaveFile->CreateBackupFile(ProcmailRcFileName); | |||
std::ofstream Output; // Write the updated contents. | |||
Output.open(ProcmailRcFileName.c_str(), std::ios::trunc); | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error opening the procmail configuration file " + ProcmailRcFileName; | |||
Temp += " for writing: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
Output << ProcmailRcFileContent; | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error writing the procmail configuration file " + ProcmailRcFileName; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
Output.close(); | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error closing the procmail configuration file " + ProcmailRcFileName; | |||
Temp += " after writing: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
if (!ReloadMta()) { | |||
std::cerr << "Unable to reload the sendmail configuration. Please reload " | |||
<< " the sendmail configuration for the integration with SNFServer to take effect."; | |||
} | |||
} | |||
void | |||
SendmailIntegrate::Unintegrate(FileBackup *SaveFile) { | |||
if (!IntegrationIsSupported) { | |||
return; | |||
} | |||
if (!IsIntegrated()) { | |||
return; | |||
} | |||
std::ifstream Input; | |||
if (Verbose()) { | |||
std::cout << "Remove integration in procmail file " << ProcmailRcFileName << "--\n"; | |||
} | |||
if (!Explain()) { | |||
Input.open(ProcmailRcFileName.c_str()); | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error opening the procmail configuration file " + ProcmailRcFileName; | |||
Temp += " for reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
std::ostringstream ContentStream; | |||
ContentStream << Input.rdbuf(); | |||
Input.close(); | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error closing the procmail configuration file " + ProcmailRcFileName; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
std::string Content; | |||
Content = ContentStream.str(); | |||
if (Verbose()) { | |||
std::cout << " Remove all occurances of\n\n" << ProcmailRcSnifferIntegration << "\n\n" | |||
<< " from" << ProcmailRcFileName << "...\n"; | |||
} | |||
std::string::size_type IntegrationBegin = std::string::npos; | |||
while ((IntegrationBegin = Content.find(ProcmailRcSnifferIntegration)) != std::string::npos) { | |||
Content.erase(IntegrationBegin, ProcmailRcSnifferIntegration.length()); | |||
} | |||
SaveFile->CreateBackupFile(ProcmailRcFileName); | |||
std::ofstream Output; // Write the updated contents. | |||
Output.open(ProcmailRcFileName.c_str(), std::ios::trunc); | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error opening the procmail configuration file " + ProcmailRcFileName; | |||
Temp += " for writing: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
Output << Content; | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error writing the procmail configuration file " + ProcmailRcFileName; | |||
Temp += ": "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
Output.close(); | |||
if (!Output) { | |||
std::string Temp; | |||
Temp = "Error closing the procmail configuration file " + ProcmailRcFileName; | |||
Temp += " after writing: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
if (!ReloadMta()) { | |||
std::cerr << "Unable to reload the sendmail configuration. Please run " | |||
<< "'sendmail reload' for the integration with SNFServer to take effect."; | |||
} | |||
} | |||
bool | |||
SendmailIntegrate::MtaIsRunningDetected() { | |||
if (Verbose()) { | |||
std::cout << "Checking whether sendmail is detected to be running..."; | |||
} | |||
bool IsRunningDetected; | |||
IsRunningDetected = (std::system(MtaIsRunningCommand.c_str()) == 0); | |||
if (Verbose()) { | |||
std::cout << (IsRunningDetected ? "yes..." : "no..."); | |||
} | |||
OutputVerboseEnd(); | |||
return IsRunningDetected; | |||
} | |||
bool | |||
SendmailIntegrate::ReloadMta() { | |||
if (!MtaIsRunningDetected()) { | |||
return true; | |||
} | |||
if (Verbose()) { | |||
std::cout << "Reloading sendmail with the command '" | |||
<< ReloadMtaCommand << "'...\n"; | |||
std::cout.flush(); | |||
} | |||
bool Succeeded; | |||
if (!Explain()) { | |||
Succeeded = (std::system(ReloadMtaCommand.c_str()) == 0); | |||
if (Verbose()) { | |||
std::cout << (Succeeded ? "succeeded..." : "failed..."); | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
return Succeeded; | |||
} | |||
bool | |||
SendmailIntegrate::IsIntegrated() { | |||
if (Verbose()) { | |||
std::cout << "Checking for any SNFServer integration in the procmail file " << ProcmailRcFileName << "..."; | |||
} | |||
if (!FileExists(ProcmailRcFileName)) { | |||
if (Verbose()) { | |||
std::cout << "file doesn't exist; sendmail is not integrated..."; | |||
} | |||
OutputVerboseEnd(); | |||
return false; | |||
} | |||
bool Integrated = false; | |||
std::ifstream Input; | |||
Input.open(ProcmailRcFileName.c_str()); // Read the contents. | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error opening the procmail configuration file " + ProcmailRcFileName; | |||
Temp += " for reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
std::string ProcmailRcFileContent; | |||
if (!Input.eof()) { | |||
std::ostringstream Buffer; | |||
Buffer << Input.rdbuf(); | |||
ProcmailRcFileContent = Buffer.str(); | |||
} | |||
Input.close(); | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error closing the procmail configuration file " + ProcmailRcFileName; | |||
Temp += " after reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
Integrated = (ProcmailRcFileContent.find(ProcmailRcSnifferIntegration) != std::string::npos); | |||
if (Verbose()) { | |||
if (Integrated) { | |||
std::cout << "found\n\n" << ProcmailRcSnifferIntegration << "\n\n..."; | |||
} else { | |||
std::cout << "none found..."; | |||
} | |||
} | |||
OutputVerboseEnd(); | |||
return Integrated; | |||
} | |||
bool | |||
SendmailIntegrate::MtaConfigurationHasProcmailForLda() { | |||
std::string File; | |||
std::ifstream Input; | |||
File = SendmailSendmailMcPath; | |||
if (Verbose()) { | |||
std::cout << "Checking sendmail configuraton file " + File | |||
<< " to verify that procmail is the Local Delivery Agent.\n"; | |||
} | |||
Input.open(File.c_str()); | |||
if (!Input) { | |||
std::string Temp; | |||
Temp = "Error opening sendmail configuration file " + File; | |||
Temp += " for reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
std::string Line; | |||
bool LdaIsProcmail = true; | |||
bool FoundLdaLine = false; | |||
while (getline(Input, Line)) { | |||
if (Line.substr(0, SendmailLdaKey.length()) == SendmailLdaKey) { // Check for LDA line. | |||
FoundLdaLine = true; | |||
if (Line.find(",", SendmailLdaKey.length()) != std::string::npos) { // Additional arguments? | |||
if (Line.find("procmail", SendmailLdaKey.length()) == std::string::npos) { // Yes. | |||
LdaIsProcmail = false; // procmail not specified in the config line. | |||
if (Verbose()) { | |||
std::cout << "The following line indicates that the sendmail LDA is not procmail:\n\n" | |||
<< Line << "\n"; | |||
} | |||
break; | |||
} else { // procmail is specified in the config line. | |||
if (Verbose()) { | |||
std::cout << "The following line indicates that the sendmail LDA is procmail, " | |||
<< "as required to integrate with SNFServer:\n\n" | |||
<< Line << "\n\n"; | |||
} | |||
break; | |||
} | |||
} else { // LDA line uses default, which is procmail. | |||
if (Verbose()) { | |||
std::cout << "The following line indicates that the sendmail LDA is procmail, " | |||
<< "as required to integrate with SNFServer:\n\n" | |||
<< Line << "\n\n"; | |||
} | |||
break; | |||
} | |||
} | |||
} | |||
Input.close(); | |||
if (Input.bad()) { | |||
std::string Temp; | |||
Temp = "Error closing the sendmail configuration file " + File; | |||
Temp += " after reading: "; | |||
Temp += strerror(errno); | |||
throw std::runtime_error(Temp); | |||
} | |||
if (Verbose() && !FoundLdaLine) { | |||
std::cout << "The absence of \"" << SendmailLdaKey << "\" indicates that the LDA is procmail, " | |||
<< "as required to integrate with SNFServer.\n"; | |||
} | |||
return LdaIsProcmail; | |||
} |
@@ -0,0 +1,82 @@ | |||
// \file SendmailIntegrate.hpp | |||
// | |||
// Copyright (C) 2012 ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file defines the SendmailIntegrate interface. | |||
// | |||
// $Id$ | |||
// | |||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||
#ifndef SendmailIntegratehpp_included | |||
#define SendmailIntegratehpp_included | |||
#include <vector> | |||
#include "MtaIntegrate.hpp" | |||
/// Class to manage the SNFServer integration with sendmail. | |||
// | |||
// This class implements the MtaIntegrate interface for sendmail. | |||
// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
class SendmailIntegrate : public MtaIntegrate { | |||
public: | |||
virtual void SetOperatingSystem(std::string OperatingSystemType); | |||
virtual void Integrate(FileBackup *SaveFile); | |||
virtual void Unintegrate(FileBackup *SaveFile); | |||
private: | |||
virtual bool MtaIsRunningDetected(); | |||
virtual bool ReloadMta(); | |||
virtual bool IsIntegrated(); | |||
bool MtaConfigurationHasProcmailForLda(); | |||
/// Directory containing the snfSniffer script. | |||
std::string SnfSnifferDirName; | |||
/// snfSniffer script file name, including the directory. | |||
std::string SnfSnifferFileName; | |||
/// Sample snfSniffer script file name, including the directory. | |||
std::string SnfSnifferSampleFileName; | |||
/// procmail system configuration file name. | |||
std::string ProcmailRcFileName; | |||
/// Integration lines for procmail configuration file. | |||
std::string ProcmailRcSnifferIntegration; | |||
/// Sendmail sendmail.mc file path. | |||
std::string SendmailSendmailMcPath; | |||
/// Sendmail sendmail.cf file path. | |||
std::string SendmailSendmailCfPath; | |||
/// Command to build and install the sendmail.cf file. | |||
std::string BuildInstallSendmailCfFile; | |||
/// Command to reload the MTA. | |||
std::string ReloadMtaCommand; | |||
/// True if integration is supported on this platform. | |||
bool IntegrationIsSupported; | |||
/// typedef for container of filenames to backup up before integrating or unintegrating. | |||
typedef std::vector<std::string> FileToBackupType; | |||
/// Files to back up before integrating or unintegrating. | |||
FileToBackupType FileToBackup; | |||
}; | |||
#endif |
@@ -0,0 +1,115 @@ | |||
// 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 SNFServer. | |||
// | |||
// 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 "SNFServerConfig.hpp" | |||
using namespace std; | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
/// Version string. | |||
const char* SNF_SERVERCONFIG_VERSION = "SNFServerConfig 0.0.1 Build: " __DATE__ " " __TIME__; | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
void RestoreFiles(SNFServerConfig *Config) { | |||
try { | |||
cerr << "Restoring all configuration files..."; | |||
Config->SaveFile.RestoreAllFilesFromBackup(); | |||
Config->SetOwnerPermissionsOfConfigFiles(); | |||
cerr << "done.\n\n" | |||
<< "Configuration files that resulted in this error are saved with a suffix \"" | |||
<< Config->SaveFile.GetFailedFileName("") << "\".\n"; | |||
} | |||
catch(exception& e) { | |||
cerr << "SNFServerConfig::SaveFile Exception: " << e.what() << endl; | |||
} | |||
} | |||
int main(int argc, char* argv[]) { | |||
SNFServerConfig SnfServerConfig; | |||
try { // Catch anything that breaks loose. | |||
if (!SnfServerConfig.GetCommandLineInput(argc, argv) || // If our command line arguments | |||
SnfServerConfig.Help()) { // don't look right, or if help is | |||
// requested then display our help | |||
SnfServerConfig.DisplayHelp(SNF_SERVERCONFIG_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_SERVERCONFIG_VERSION << endl; // watchers. | |||
cout << "Debug Mode" << endl; | |||
SnfServerConfig.SetDebug(true); | |||
} | |||
SnfServerConfig.ExecuteCommand(); | |||
} // That's all folks. | |||
catch(exception& e) { // Report any normal exceptions. | |||
cerr << "\n\nSNFServerConfig Exception: " << e.what() << endl << endl; | |||
RestoreFiles(&SnfServerConfig); | |||
return(-1); | |||
} | |||
catch (snfCFGmgr::LoadFailure) { // Error loading configuration file. | |||
cerr << "\n\nsnfCFGmgr Exception: Unable to load the configuration file " | |||
<< SnfServerConfig.GetConfigFileName() << endl << endl; | |||
RestoreFiles(&SnfServerConfig); | |||
return(-1); | |||
} | |||
catch(...) { // Report any unexpected exceptions. | |||
cerr << "\n\nSNFServerConfig Panic! Unknown Exception!" << endl << endl; | |||
RestoreFiles(&SnfServerConfig); | |||
return(-1); | |||
} | |||
return 0; // Normally we return zero. | |||
} |