// /file SendmailIntegrate.cpp // // Copyright (C) 2011, ARM Research Labs, LLC. // See www.armresearch.com for the copyright terms. // // This file contains the functions for SendmailIntegrate. // // $Id$ // /////////////////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include "SendmailIntegrate.hpp" ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Configuration. //////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// const std::string SnfMilterSendmailMcSearchString("Added by SNFMilterConfig"); const std::string SnfMilterSendmailMcIntegrationString("INPUT_MAIL_FILTER(`SNFMilter', `S=unix:/var/snf-milter/socket')dnl # Added by SNFMilterConfig"); const std::string MtaIsRunningCommand("ps axl | grep -v grep | grep -q ' sendmail: '"); ////////////////////////////////////////////////////////////////////////////////////////////////////////// // End of configuration. ///////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// void SendmailIntegrate::SetOperatingSystem(std::string OperatingSystemType) { if ("OpenBSD" == OperatingSystemType) { SendmailSendmailMcPath = "/etc/mail/sendmail.mc"; SendmailSendmailCfPath = "/etc/mail/sendmail.cf"; ReloadMtaCommand = "/usr/local/sbin/postfix reload"; FileToBackup.push_back(SendmailSendmailMcPath); FileToBackup.push_back(SendmailSendmailCfPath); } else if ("FreeBSD" == OperatingSystemType) { SendmailSendmailMcPath = "/etc/mail/sendmail.mc"; SendmailSendmailCfPath = "/etc/mail/sendmail.cf"; ReloadMtaCommand = "/usr/local/sbin/postfix reload"; FileToBackup.push_back(SendmailSendmailMcPath); FileToBackup.push_back(SendmailSendmailCfPath); } else if ("Ubuntu" == OperatingSystemType) { SendmailSendmailMcPath = "/etc/mail/sendmail.mc"; SendmailSendmailCfPath = "/etc/mail/sendmail.cf"; BuildInstallSendmailCfFile = "(cd /etc/mail; make)"; ReloadMtaCommand = "/usr/sbin/service sendmail reload"; FileToBackup.push_back(SendmailSendmailMcPath); FileToBackup.push_back(SendmailSendmailCfPath); } else if ("RedHat" == OperatingSystemType) { SendmailSendmailMcPath = "/etc/mail/sendmail.mc"; SendmailSendmailCfPath = "/etc/mail/sendmail.cf"; BuildInstallSendmailCfFile = "(cd /etc/mail; make)"; ReloadMtaCommand = "/sbin/service sendmail reload"; FileToBackup.push_back(SendmailSendmailMcPath); FileToBackup.push_back(SendmailSendmailCfPath); } else if ("Suse" == OperatingSystemType) { SendmailSendmailMcPath = "/etc/mail/linux.mc"; SendmailSendmailCfPath = "/etc/mail/sendmail.cf"; BuildInstallSendmailCfFile = "(cd /etc/mail; rm sendmail.cf; m4 /etc/mail/linux.mc > sendmail.cf)"; ReloadMtaCommand = "/usr/sbin/postfix 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()); } } void SendmailIntegrate::Integrate(FileBackup *SaveFile) { if (IsIntegrated()) { return; } if (Verbose()) { std::cout << "Add to sendmail file " << SendmailSendmailMcPath << ": '" << SnfMilterSendmailMcIntegrationString << "' and generate new " << SendmailSendmailCfPath << " file with the command '" << BuildInstallSendmailCfFile << "'..."; } if (!Explain()) { for (FileToBackupType::iterator iFile = FileToBackup.begin(); iFile != FileToBackup.end(); iFile++) { SaveFile->CreateBackupFile(*iFile); // Save any existing file. } std::ofstream Output; // Append the configuration. Output.open(SendmailSendmailMcPath.c_str(), std::ios::app); if (!Output) { std::string Temp; Temp = "Error opening the sendmail configuration file " + SendmailSendmailMcPath; Temp += " for writing: "; Temp += strerror(errno); throw std::runtime_error(Temp); } Output << SnfMilterSendmailMcIntegrationString << "\n"; if (!Output) { std::string Temp; Temp = "Error appending to the sendmail configuration file " + SendmailSendmailMcPath; Temp += ": "; Temp += strerror(errno); throw std::runtime_error(Temp); } Output.close(); if (!Output) { std::string Temp; Temp = "Error closing the sendmail configuration file " + SendmailSendmailMcPath; Temp += " after appending: "; Temp += strerror(errno); throw std::runtime_error(Temp); } if (std::system(BuildInstallSendmailCfFile.c_str()) != 0) { std::string Temp; Temp = "Error generating sendmail configuration file " + SendmailSendmailCfPath; 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 SNFMilter to take effect."; } } void SendmailIntegrate::Unintegrate(FileBackup *SaveFile) { if (!IsIntegrated()) { return; } std::ifstream Input; if (Verbose()) { std::cout << "Remove integration in sendmail file " << SendmailSendmailMcPath << "--\n"; } if (!Explain()) { for (FileToBackupType::iterator iFile = FileToBackup.begin(); iFile != FileToBackup.end(); iFile++) { SaveFile->CreateBackupFile(*iFile); // Save any existing file. } Input.open(SendmailSendmailMcPath.c_str()); // Read the contents. if (!Input) { std::string Temp; Temp = "Error opening the sendmail configuration file " + SendmailSendmailMcPath; Temp += " for reading: "; Temp += strerror(errno); throw std::runtime_error(Temp); } std::string Content; std::string Line; while (getline(Input, Line)) { if (std::string::npos != Line.find(SnfMilterSendmailMcSearchString)) { // Check for integration line. if (Verbose()) { std::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. std::string Temp; Temp = "Error reading the sendmail configuration file " + SendmailSendmailMcPath; Temp += ": "; Temp += strerror(errno); throw std::runtime_error(Temp); } Input.close(); if (Input.bad()) { std::string Temp; Temp = "Error closing the sendmail configuration file " + SendmailSendmailMcPath; Temp += " after reading: "; Temp += strerror(errno); throw std::runtime_error(Temp); } std::ofstream Output; // Write the updated contents. Output.open(SendmailSendmailMcPath.c_str(), std::ios::trunc); if (!Output) { std::string Temp; Temp = "Error opening the sendmail configuration file " + SendmailSendmailMcPath; Temp += " for writing: "; Temp += strerror(errno); throw std::runtime_error(Temp); } Output << Content; if (!Output) { std::string Temp; Temp = "Error writing the sendmail configuration file " + SendmailSendmailMcPath; Temp += ": "; Temp += strerror(errno); throw std::runtime_error(Temp); } Output.close(); if (!Output) { std::string Temp; Temp = "Error closing the sendmail configuration file " + SendmailSendmailMcPath; Temp += " after writing: "; Temp += strerror(errno); throw std::runtime_error(Temp); } if (std::system(BuildInstallSendmailCfFile.c_str()) != 0) { // Rebuild and install the sendmail configuration file. std::string Temp; Temp = "Error generating sendmail configuration file " + SendmailSendmailCfPath; throw std::runtime_error(Temp); } } OutputVerboseEnd(); if (!ReloadMta()) { std::cerr << "Unable to reload the sendmail configuration. Please run " << "'sendmail reload' for the integration with SNFMilter 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 SNFMilter integration in the sendmail file " << SendmailSendmailMcPath << "..."; } if (!FileExists(SendmailSendmailMcPath)) { if (Verbose()) { std::cout << "file doesn't exist; sendmail is not integrated..."; } OutputVerboseEnd(); return false; } bool Integrated = false; std::ifstream Input; Input.open(SendmailSendmailMcPath.c_str()); // Read the contents. if (!Input) { std::string Temp; Temp = "Error opening the sendmail configuration file " + SendmailSendmailMcPath; Temp += " for reading: "; Temp += strerror(errno); throw std::runtime_error(Temp); } std::string Line; while (getline(Input, Line)) { if (std::string::npos != Line.find(SnfMilterSendmailMcSearchString)) { // Check for integration line. Integrated = true; // Found it. break; } } Input.close(); if (Input.bad()) { std::string Temp; Temp = "Error closing the sendmail configuration file " + SendmailSendmailMcPath; Temp += " after reading: "; Temp += strerror(errno); throw std::runtime_error(Temp); } if (Verbose()) { if (Integrated) { std::cout << "found '" << Line << "'..."; } else { std::cout << "none found..."; } } OutputVerboseEnd(); return Integrated; }