// /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("-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) { std::string ExclusiveCommands; std::string ExclusiveCommandsHelp; ExclusiveCommands = IntegrateWithPostfixKey + " | "; ExclusiveCommands += IntegrateWithSendmailKey + " | "; ExclusiveCommands += IntegrateWithNoneKey; ExclusiveCommandsHelp = " -mta=postfix Integrate with postfix and start/reload postfix\n"; ExclusiveCommandsHelp += " -mta=sendmail Integrate with sendmail and start/reload sendmail\n"; ExclusiveCommandsHelp += " -mta=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" << "If snf-config-file is not specified, then the following file is used if it exists:\n\n" << " " << DefaultConfigFile << "\n\n" << "If snf-config-file is not specified and the above file doesn't exist, then it is\n" << "copied from the following file:\n\n" << " " << SampleConfigFile << "\n\n" << "If integration with an MTA is specified, that MTA is started if it isn't running,\n" << "or the MTA's configuration is reloaded if it 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)) { 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); } void SNFMilterConfig::ExecuteCommand() { switch (Command) { case SetupRepairCommand: CheckAndSetConfigFileName(DefaultConfigFile); // Load the config file name if not specified. 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. SetupRepair(SampleIdentityFile); SetupRepairSocketDir(); break; case UpdateCredentialsCommand: CheckAndSetConfigFileName(DefaultConfigFile); // Load the config file name if not specified. LoadConfig(); LoadInfo(); // Load the file paths. LoadSocketInfo(); // Load the socket path. UpdateRulebaseScriptCredentials(); DownloadRulebase(); UpdateIdentityFile(); break; case IntegrateWithPostfixCommand: break; case IntegrateWithSendmailCommand: break; case IntegrateWithNoneCommand: break; case StartSnifferCommand: CheckAndSetConfigFileName(DefaultConfigFile); LoadConfig(); LoadInfo(); LoadSocketInfo(); StartSniffer("snf-milter start", ApplicationName); break; case StopSnifferCommand: CheckAndSetConfigFileName(DefaultConfigFile); LoadConfig(); LoadInfo(); LoadSocketInfo(); 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_IWGRP | S_IXGRP); SetOwnerGroup(SocketDir); } OutputVerboseEnd(); } void SNFMilterConfig::SaveFileState() { if (!Explain()) { SaveFile.CreateBackupFile(GetRulebaseScriptName()); if (UpdateCredentialsSpecified()) { SaveFile.CreateBackupFile(GetRulebaseFileName()); } SaveFile.CreateBackupFile(GetIdentityFileName()); SaveFile.CreateBackupFile(GetIgnoreListFileName()); } } 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()); } } } void SNFMilterConfig::UnintegrateWithAllExcept(std::string Except) { if (Except != "postfix") { Postfix.Unintegrate(&SaveFile); } #if 0 if (Except != "sendmail") { Sendmail.Unintegrate(&SaveFile); } #endif }