// main.cpp // // Copyright (C) 2007, ARM Research Labs, LLC. // See www.armresearch.com for the copyright terms. // // This is the entry point for the SNF Milter. // The main() function acquires the configuration file path, sets up the // SNF engine, and passes control to the SNFMilter module via runSNFMilter(). // // SNFMilter() makes use of the SNF engine until it is dismissed by the MTA via // the appropriate libmilter call. // // While SNFMilter() is running, it will get new configuration data for each // scan it is asked to perform. A configuration packet will be produced on // demand by the main module. The main module will check the configuration once // every second or so to make sure it has the correct current data. The // configuration data structure is defined in SNFMilter.hpp. // // When the SNFMilter() function returns, the main() function closes down the // SNF Engine and exits the program. #include #include #include #include #include "SNFMulti.hpp" #include "SNFMilter.hpp" #include "config.h" using namespace std; const char* SNF_MILTER_VERSION = "SNFMilter " PACKAGE_VERSION " Build: " __DATE__ " " __TIME__; static const string XCIShutdownResponse = "\n"; class XCIShutdownWatcher : public snfXCIServerCommandHandler { // Shutdown watcher. public: XCIShutdownWatcher(){} string processXCIRequest(snf_xci& X) { // Here is how we process requests. if(0 == X.xci_server_command.find("shutdown")) { // If we find shutdown then smfi_stop(); // Stop processing messages. return XCIShutdownResponse; // respond with a message. } // If we get some other request return XCIErrorResponse; // return the error response. } }; class SignalCatcher : public Thread { // Class to catch a signal. private: sigset_t *MySignalSet; snf_RulebaseHandler *MyRulebase; public: SignalCatcher(sigset_t *Signal_Set, snf_RulebaseHandler* Rulebase) : // Construct. MySignalSet(Signal_Set), // Set of signals to catch. MyRulebase(Rulebase) { // Used for error logging. run(); // Start the thread. } void myTask() { int ReceivedSignal; int Status = sigwait(MySignalSet, &ReceivedSignal); if (0 != Status) { // Log error. ostringstream Temp; Temp << "Error waiting for signal: " << strerror(Status) << "."; MyRulebase->logThisError("Signal Catcher", 1, Temp.str()); return; } smfi_stop(); // Stop processing. } }; const int CorrectARGc = 2; // How many arguments we expect. void displayHelp() { // Display some help. cout << SNF_MILTER_VERSION << endl << "Copyright (C) 2007, ARM Research Labs, LLC (www.armresearch.com)" << endl << endl << "Use snfmilter " << endl << "Example: /home/snfmilter/snfmilter /home/snfmilter/snf_milter.xml" << endl; }; int main(int argc, char* argv[]) { // Get and check the command line arguments. if(CorrectARGc != argc) { // If our command line arguments displayHelp(); // don't look right then display return 0; // our help screen. } 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 << "Debug Mode" << endl; // watchers. } sigset_t SignalSet; // Set of signals to mask. SignalCatcher *SigCatcher; // Object to catch signal. try { // Catch anything that breaks loose. int PthreadStatus; if ( (0 != sigemptyset(&SignalSet)) || // Mask signal for this thread and // all threads to be created. (0 != sigaddset(&SignalSet, ShutdownSignal)) ) { ostringstream Temp; Temp << "Error masking signal on startup: " << strerror(errno) << "."; throw runtime_error(Temp.str()); } PthreadStatus = pthread_sigmask(SIG_BLOCK, &SignalSet, 0); if (0 != PthreadStatus) { ostringstream Temp; Temp << "Error masking signal on startup (pthread_sigmask): " << strerror(PthreadStatus) << "."; throw runtime_error(Temp.str()); } snf_RulebaseHandler* MilterRulebase = new snf_RulebaseHandler(); // Allocate a rulebase handler. MilterRulebase->PlatformVersion(SNF_MILTER_VERSION); // Record our version identification. XCIShutdownWatcher ShutdownWatcher; // Make a server shutdown processor MilterRulebase->XCIServerCommandHandler(ShutdownWatcher); // and register it with the engine. MilterRulebase->open(argv[1], "", ""); // Open the rulebase. SNFMilterContextPool* MilterContexts = new SNFMilterContextPool(MilterRulebase); // Create the Milter Context Pool. SigCatcher = new SignalCatcher(&SignalSet, MilterRulebase); // Create thread object to catch the signal. runLibMilter(MilterContexts, DebugMode); // Run the milter. ThreadState const &SigCatcherState = SigCatcher->MyState(); if (Thread::ThreadStarted.Name == SigCatcherState.Name) { // Is the signal catcher thread running? PthreadStatus = pthread_kill(SigCatcher->getMyThread(), ShutdownSignal); // Yes. Send it a signal. if (0 == PthreadStatus) { SigCatcher->join(); // Wait for signal catcher to complete. } else { ostringstream Temp; Temp << "Error terminating signal catcher: " << strerror(PthreadStatus) << "."; throw runtime_error(Temp.str()); } } delete MilterContexts; // Destroy the context pool. MilterContexts = 0; // Forget it. MilterRulebase->close(); // Close down the rulebase handler. delete MilterRulebase; // Destroy the rulebase. MilterRulebase = 0; // Forget it. delete SigCatcher; // Destroy the signal catcher. SigCatcher = 0; // Forget it. } // That's all folks. catch(exception& e) { // Report any normal exceptions. cerr << "SNFMilter Exception: " << e.what() << endl; } catch(...) { // Report any unexpected exceptions. cerr << "SNFMilter Panic! Unknown Exception!" << endl; } return 0; // Normally we return zero. }