// /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 #include #include #include #include #include #include #include #include #include #include #include #include #include #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::SampleConfigFile("C:\\SNF\\SNFMilter.xml.sample"); const std::string SNFMilterConfig::SampleIdentityFile("C:\\SNF\\identity.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::SampleConfigFile(DEFAULT_CONFIG_DIR "/snf-milter/SNFMilter.xml.sample"); const std::string SNFMilterConfig::SampleIdentityFile(DEFAULT_CONFIG_DIR "/snf-milter/identity.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::SampleConfigFile(""); const std::string SNFMilterConfig::SampleIdentityFile(""); #endif #endif const string SNFMilterConfig::ApplicationName("SNFMilter"); const string IntegrateWithNoneKey("-with=none"); const string IntegrateWithPostfixKey("-with=postfix"); const string IntegrateWithSendmailKey("-with=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) { 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" << "SNFMilterConfig " << UtilityConfig::HelpCommandLine(ExclusiveCommands) << "\n\n" << "SNFMilterConfig " << 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 SNFMilterConfig::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"; throw 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 SNFMilterConfig::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. LoadSocketInfo(); // Load the socket path. switch (Command) { case SetupRepairCommand: SetupRepair(SampleIdentityFile); SetupRepairSocketDir(); break; case UpdateCredentialsCommand: UpdateRulebaseScriptCredentials(); DownloadRulebase(); UpdateIdentityFile(); break; case IntegrateWithPostfixCommand: UnintegrateWithAllExcept("postfix"); Postfix.Integrate(&SaveFile); break; case IntegrateWithSendmailCommand: UnintegrateWithAllExcept("sendmail"); Sendmail.Integrate(&SaveFile); break; case IntegrateWithNoneCommand: UnintegrateWithAllExcept(); break; case StartSnifferCommand: LoadCredentials(); StartSniffer("snf-milter start", ApplicationName); break; case StopSnifferCommand: LoadCredentials(); StopSniffer("snf-milter stop", ApplicationName); break; default: break; } } 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::SetupRepairSocketDir() { 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_IXGRP); SetOwnerGroup(SocketDir); } OutputVerboseEnd(); } void SNFMilterConfig::SaveFileState() { if (!Explain()) { SaveFile.CreateBackupFile(GetRulebaseScriptName()); if (UpdateCredentialsSpecified()) { SaveFile.CreateBackupFile(GetRulebaseFileName()); } SaveFile.CreateBackupFile(GetIdentityFileName()); SaveFile.CreateBackupFile(GetIgnoreListFileName()); } } #if 0 void SNFMilterConfig::DoIntegrationCommand() { switch (Command) { case NoCommand: break; case IntegrateWithNoneCommand: UnintegrateWithAllExcept(); break; case IntegrateWithPostfixCommand: UnintegrateWithAllExcept("postfix"); Postfix.Integrate(&SaveFile); break; case IntegrateWithSendmailCommand: UnintegrateWithAllExcept("sendmail"); Sendmail.Integrate(&SaveFile); break; default: { ostringstream Temp; Temp << "Internal error in SNFMilterConfig::DoIntegrationCommand: Invalid value of command: " << Command; throw runtime_error(Temp.str()); } } } #endif void SNFMilterConfig::UnintegrateWithAllExcept(std::string Except) { if (Except != "postfix") { Postfix.Unintegrate(&SaveFile); } if (Except != "sendmail") { Sendmail.Unintegrate(&SaveFile); } }