Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

SNFMilter.cpp 62KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
  1. // SNFMilter.cpp
  2. // Copyright (C) 2008 ARM Research Labs, LLC.
  3. // See www.armresearch.com for the copyright terms.
  4. //
  5. // This file contains the "guts" of the SNFMilter interface. Specifically,
  6. // the SNFMilter() function.
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <errno.h>
  10. #include <unistd.h>
  11. #include <grp.h>
  12. #include "SNFMulti.hpp"
  13. #include "configuration.hpp"
  14. #include "SNFMilter.hpp"
  15. #include "config.h"
  16. #include <syslog.h>
  17. #include <sstream>
  18. #if SMFI_VERSION > 3
  19. #define NEW_LIBMILTER
  20. #endif
  21. SNFMilterContextPool* MilterContexts = 0; // The global contexts handle.
  22. bool MilterDebugMode; // True if debug mode is on.
  23. sfsistat SkipReturn = SMFIS_CONTINUE; // libmilter return value when further
  24. // callbacks of the same type are to be skipped.
  25. /// Get the connection context object.
  26. //
  27. // \param[in] Ctx is the libmilter context object.
  28. //
  29. // \returns the pointer to the connection context object.
  30. //
  31. // \throws runtime_error if the obtained pointer is 0.
  32. //
  33. SNFMilterContext*
  34. getContextFromCtx(SMFICTX* Ctx) {
  35. SNFMilterContext* Context = (SNFMilterContext*) smfi_getpriv(Ctx); // Get the context object.
  36. if(0 == Context) throw runtime_error("Got NULL from smfi_getpriv()");
  37. return Context;
  38. }
  39. /// Get a new connection object and assign it to the context.
  40. //
  41. // \param[in] Ctx is the libmilter context object.
  42. //
  43. // \returns the pointer to the connection context object.
  44. //
  45. // \throws runtime_error if the obtained pointer is 0.
  46. //
  47. SNFMilterContext*
  48. assignContextToCtx(SMFICTX* Ctx) {
  49. SNFMilterContext* Context = MilterContexts->grab(); // Get any existing context object.
  50. if(0 == Context) // Check address.
  51. throw runtime_error("Got NULL from MilterContexts->grab()");
  52. smfi_setpriv(Ctx, Context); // Save the context object.
  53. Context->ConnectionData.clear(); // Clear the connection context object.
  54. return Context;
  55. }
  56. // Function to output an info message.
  57. void logInfo(const string ContextName, int Code, std::string Message) {
  58. cout << ContextName << " (code " << Code << "): " << Message << endl;
  59. #if 0
  60. syslog(LOG_MAIL | LOG_DEBUG, "%s", Message.c_str()); // Output to system mail log.
  61. #endif
  62. MilterContexts->logThisInfo(ContextName, Code, Message); // Log message.
  63. }
  64. // Function to output an error message.
  65. void logError(const string &ContextName, const int &Code, const std::string &Message) {
  66. cout << ContextName << " (code " << Code << "): " << Message << endl;
  67. #if 0
  68. syslog(LOG_MAIL | LOG_DEBUG, "%s", Message.c_str()); // Output to system mail log.
  69. #endif
  70. MilterContexts->logThisError(ContextName, Code, Message); // Log message.
  71. }
  72. class ResultActionHandler : public Configurator {
  73. private:
  74. SNFMilterEngine* Target;
  75. public:
  76. ResultActionHandler(SNFMilterEngine* T) : Target(T) {}
  77. void operator()(ConfigurationElement& E, ConfigurationData& D) {
  78. Target->setResultAction(
  79. Code,
  80. (Action >= Allow && Action <= Quarantine) ?
  81. static_cast<SNFMilterAction>(Action)
  82. : Allow
  83. );
  84. }
  85. int Code;
  86. int Action;
  87. };
  88. const int NoSuchCode = -1; // Magic number for no such code
  89. const int NoSuchAction = -1; // Magic number for no such action
  90. void SNFMilterEngine::readConfiguration() { // Parse the configuration.
  91. string NewConfiguration = myRulebase->PlatformConfiguration(); // Get the latest configuration.
  92. if(0 != RunningConfiguration.compare(NewConfiguration)) { // If it does not match, read it!
  93. RunningConfiguration = NewConfiguration; // Capture the latest.
  94. for(int i = 1; i < ResultCodesCount; i++) ResultActions[i] = NoAction; // Init Result/Action config.
  95. ResultActions[0] = Allow;
  96. NonZeroAction = NoAction; // NoAction if no configuration for
  97. // non-zero result.
  98. ResultActionHandler ResultActionConfigurator(this); // Create a Result/Action handler.
  99. ConfigurationElement Reader("milter"); // Create a configuration reader.
  100. Reader
  101. .Element("connect")
  102. .Element("white")
  103. .Attribute("action", reinterpret_cast<int&>(WhiteAction), static_cast<int>(Allow))
  104. .Mnemonic("Allow", AllowActionMnemonic)
  105. .Mnemonic("Accept", AcceptActionMnemonic)
  106. .Mnemonic("Retry", RetryActionMnemonic)
  107. .Mnemonic("Reject", RejectActionMnemonic)
  108. .Mnemonic("Discard", DiscardActionMnemonic)
  109. .Mnemonic("Quarantine", QuarantineActionMnemonic)
  110. .End("white")
  111. .Element("caution")
  112. .Attribute("action", reinterpret_cast<int&>(CautionAction), static_cast<int>(Allow))
  113. .Mnemonic("Allow", AllowActionMnemonic)
  114. .Mnemonic("Accept", AcceptActionMnemonic)
  115. .Mnemonic("Retry", RetryActionMnemonic)
  116. .Mnemonic("Reject", RejectActionMnemonic)
  117. .Mnemonic("Discard", DiscardActionMnemonic)
  118. .Mnemonic("Quarantine", QuarantineActionMnemonic)
  119. .End("caution")
  120. .Element("black")
  121. .Attribute("action", reinterpret_cast<int&>(BlackAction), static_cast<int>(Allow))
  122. .Mnemonic("Allow", AllowActionMnemonic)
  123. .Mnemonic("Accept", AcceptActionMnemonic)
  124. .Mnemonic("Retry", RetryActionMnemonic)
  125. .Mnemonic("Reject", RejectActionMnemonic)
  126. .Mnemonic("Discard", DiscardActionMnemonic)
  127. .Mnemonic("Quarantine", QuarantineActionMnemonic)
  128. .End("black")
  129. .Element("truncate")
  130. .Attribute("action", reinterpret_cast<int&>(TruncateAction), static_cast<int>(Allow))
  131. .Mnemonic("Allow", AllowActionMnemonic)
  132. .Mnemonic("Accept", AcceptActionMnemonic)
  133. .Mnemonic("Retry", RetryActionMnemonic)
  134. .Mnemonic("Reject", RejectActionMnemonic)
  135. .Mnemonic("Discard", DiscardActionMnemonic)
  136. .Mnemonic("Quarantine", QuarantineActionMnemonic)
  137. .End("truncate")
  138. .End("connect")
  139. .Element("scan")
  140. .Element("result")
  141. .atEndCall(ResultActionConfigurator)
  142. .Attribute("code", ResultActionConfigurator.Code, NoSuchCode)
  143. .Attribute("action", ResultActionConfigurator.Action, NoSuchAction)
  144. .Mnemonic("Allow", AllowActionMnemonic)
  145. .Mnemonic("Accept", AcceptActionMnemonic)
  146. .Mnemonic("Retry", RetryActionMnemonic)
  147. .Mnemonic("Reject", RejectActionMnemonic)
  148. .Mnemonic("Discard", DiscardActionMnemonic)
  149. .Mnemonic("Quarantine", QuarantineActionMnemonic)
  150. .End("result")
  151. .Element("nonzero")
  152. .Attribute("action", reinterpret_cast<int&>(NonZeroAction), static_cast<int>(NoAction))
  153. .Mnemonic("Allow", AllowActionMnemonic)
  154. .Mnemonic("Accept", AcceptActionMnemonic)
  155. .Mnemonic("Retry", RetryActionMnemonic)
  156. .Mnemonic("Reject", RejectActionMnemonic)
  157. .Mnemonic("Discard", DiscardActionMnemonic)
  158. .Mnemonic("Quarantine", QuarantineActionMnemonic)
  159. .End("nonzero")
  160. .End("scan")
  161. .End("milter");
  162. ConfigurationData ConfigurationData( // Convert our configuration string
  163. NewConfiguration.c_str(), // to a configuration data buffer.
  164. NewConfiguration.length());
  165. Reader.initialize(); // Initialize the defaults.
  166. Reader.interpret(ConfigurationData); // Read the new configuration.
  167. }
  168. }
  169. void SNFMilterEngine::setResultAction(int Result, SNFMilterAction Action) { // Set a result / action pair.
  170. if(
  171. 0 <= Result &&
  172. ResultCodesCount > Result // If the Result code is in
  173. ) { ResultActions[Result] = Action; } // range then set the action.
  174. }
  175. void SNFMilterEngine::checkConfiguration() { // Reload the config if it is old.
  176. if(ConfigurationCheckTime.isExpired()) readConfiguration();
  177. }
  178. SNFMilterEngine::SNFMilterEngine(snf_RulebaseHandler* R) : // Construct the engine.
  179. myRulebase(R), // Remember our rulebase.
  180. myEngine(0), // We need to set this later.
  181. WhiteAction(Allow), // Initialize our default actions.
  182. CautionAction(Allow),
  183. BlackAction(Allow),
  184. TruncateAction(Allow),
  185. ConfigurationCheckTime(ConfigurationLifetime)
  186. {
  187. myEngine = new snf_EngineHandler(); // Create an engine handler.
  188. myEngine->open(myRulebase); // Connect it to the rulebase.
  189. readConfiguration(); // Read our configuration.
  190. }
  191. SNFMilterEngine::~SNFMilterEngine() { // Destroy the engine.
  192. try {
  193. ScopeMutex EngineLock(ConfigMutex); // Don't die while scanning.
  194. if(myEngine) { // If we're not dead then die.
  195. myEngine->close(); // Close the engine.
  196. delete myEngine; // Delete it.
  197. myEngine = 0; // Forget it.
  198. myRulebase = 0; // Forget (don't delete) this too.
  199. }
  200. }
  201. catch(...) {} // Silently capture exceptions.
  202. }
  203. SNFMilterAction SNFMilterEngine::scanIP(unsigned long int IP) { // Scans an IP.
  204. IPTestRecord Tester(IP); // Make up a test record for this IP.
  205. ScopeMutex ConfigurationLock(ConfigMutex); // Lock our configuration.
  206. if(0 == myEngine) throw runtime_error("Null engine when scanning IP"); // Skip safely if we're down.
  207. checkConfiguration(); // Re-read our config if it is old.
  208. myRulebase->performIPTest(Tester); // Tun it past the engine.
  209. SNFMilterAction TestResult = Allow; // Allow by default.
  210. switch(Tester.R) { // Convert the result to an action.
  211. case White: { TestResult = WhiteAction; break; } // If the IP scan range is recognized
  212. case Caution: { TestResult = CautionAction; break; } // in our configuration then we will
  213. case Black: { TestResult = BlackAction; break; } // return the action code that is
  214. case Truncate: { TestResult = TruncateAction; break; } // configured. Otherwise we will return
  215. default: break;
  216. } // the default "Allow" action.
  217. return TestResult; // Tell them what we've got.
  218. }
  219. SNFMilterAction SNFMilterEngine::scanMessage( // Scans a message.
  220. const unsigned char* bfr, // Requires a pointer to the buffer.
  221. int length) { // Requires the buffer length.
  222. ScopeMutex ConfigurationLock(ConfigMutex); // Lock the configuration.
  223. if(0 == myEngine) throw runtime_error("Null engine when scanning message"); // Skip safely if we're down.
  224. checkConfiguration(); // Re-read our config if it is old.
  225. int R = myEngine->scanMessage(bfr, length, "", 0); // Scan the message & get the result.
  226. if(0 > R || ResultCodesCount <= R) return Error; // If R is out of range, return Error.
  227. if (0 == R || NoAction != ResultActions[R]) return ResultActions[R]; // Return the translated action.
  228. return NonZeroAction;
  229. }
  230. string SNFMilterEngine::XHeaders() { // Return X headers from last scan.
  231. ScopeMutex EngineLock(ConfigMutex); // Use myEngine safely.
  232. if(0 == myEngine) return ""; // Return no headers if dead.
  233. return myEngine->getXHDRs(); // Simply return them.
  234. }
  235. //// SNFMilterContext
  236. SNFMilterContext::SNFMilterContext(snf_RulebaseHandler *myRulebase) :
  237. milterEngine(myRulebase),
  238. MessageData(MailBufferReserveSize) {}
  239. SNFMilterContext::~SNFMilterContext() {}
  240. /// Return the local received header.
  241. //
  242. // \returns the local received header.
  243. //
  244. string
  245. SNFMilterContext::getLocalReceivedHeader() {
  246. string locHeader;
  247. locHeader = "Received: from <" + ConnectionData.HostName;
  248. locHeader += "> [" + (string) ConnectionData.HostIP;
  249. locHeader += "] by " PACKAGE_NAME;
  250. return locHeader;
  251. }
  252. /// Map return value from SNFMilterEngine scan to libmilter return value.
  253. //
  254. // \param[in] MilterAction is the return from an SNFMilterEngine scan.
  255. //
  256. // \returns the return value for the libmilter callback.
  257. //
  258. // \throws std::out_of_range if MilterAction of out of range.
  259. //
  260. sfsistat
  261. SNFMilterContext::smfisReturn(SNFMilterAction MilterAction) {
  262. static const sfsistat ReturnValue[] = {
  263. SMFIS_CONTINUE,
  264. SMFIS_ACCEPT,
  265. SMFIS_TEMPFAIL,
  266. SMFIS_REJECT,
  267. SMFIS_DISCARD,
  268. SMFIS_CONTINUE
  269. };
  270. if ( (MilterAction < 0) || (MilterAction >= NMilterActions) ) {
  271. ostringstream Temp;
  272. Temp << "Illegal value of SNFMilterAction in SNFMilterContext::smfisReturn ("
  273. << MilterAction << ") while processing message from "
  274. << MessageData.SenderAddress
  275. << " (connection from " << ConnectionData.HostName << " ("
  276. << (string) ConnectionData.HostIP << ").";
  277. throw std::out_of_range(Temp.str());
  278. }
  279. return ReturnValue[MilterAction];
  280. }
  281. //// SNFMilterContextPool
  282. SNFMilterContextPool::SNFMilterContextPool(snf_RulebaseHandler* Rulebase) : // Ctor needs a live rulebase handler.
  283. myRulebase(Rulebase), // Capture the rulebase handler.
  284. MilterSocketPort(0) {
  285. string NewConfiguration = myRulebase->PlatformConfiguration(); // Get the latest configuration.
  286. ConfigurationElement Reader("milter"); // Create a configuration reader.
  287. Reader
  288. .Element("socket")
  289. .Attribute("type", reinterpret_cast<int&>(MilterSocketType), static_cast<int>(NOMilterSocket))
  290. .Mnemonic("unix", UNIXMilterSocketMnemonic)
  291. .Mnemonic("tcp", TCPMilterSocketMnemonic)
  292. .Attribute("path", MilterSocketPath, "")
  293. .Attribute("group", MilterSocketGroup, "")
  294. .Attribute("ip", MilterSocketIP, "")
  295. .Attribute("port", MilterSocketPort, 0)
  296. .End("socket")
  297. .End("milter");
  298. ConfigurationData ConfigurationData( // Convert our configuration string
  299. NewConfiguration.c_str(), // to a configuration data buffer.
  300. NewConfiguration.length());
  301. Reader.initialize(); // Initialize the defaults.
  302. Reader.interpret(ConfigurationData); // Read the new configuration.
  303. switch (MilterSocketType) { // Named pipe.
  304. case UNIXMilterSocket:
  305. if (0 == MilterSocketPath.size()) { // Path specified?
  306. ostringstream Temp; // No.
  307. Temp << "Path needs to be specified for socket type \"unix\"";
  308. throw runtime_error(Temp.str());
  309. }
  310. if ( (0 != MilterSocketIP.size()) || // These should not be specified.
  311. (0 != MilterSocketPort) ) {
  312. ostringstream Temp;
  313. Temp << "IP (" << MilterSocketIP << ") and/or port (" << MilterSocketPort
  314. << ") were specified for socket type \"unix\". They should not be specified.";
  315. throw runtime_error(Temp.str());
  316. }
  317. break;
  318. case TCPMilterSocket:
  319. if (0 == MilterSocketIP.size()) { // IP/host specified?
  320. ostringstream Temp; // No.
  321. Temp << "Host or IP address needs to be specified for socket type \"inet\"";
  322. throw runtime_error(Temp.str());
  323. }
  324. if (0 == MilterSocketPort) { // Port specified?
  325. ostringstream Temp; // No.
  326. Temp << "Port needs to be specified for socket type \"inet\"";
  327. throw runtime_error(Temp.str());
  328. }
  329. if ( (0 != MilterSocketPath.size()) || // These should not be specified.
  330. (0 != MilterSocketGroup.size()) ) {
  331. ostringstream Temp;
  332. Temp << "Path (" << MilterSocketPath << ") and/or group (" << MilterSocketGroup
  333. << ") were specified for socket type \"inet\". They should not be specified.";
  334. throw runtime_error(Temp.str());
  335. }
  336. break;
  337. case NOMilterSocket:
  338. {
  339. ostringstream Temp;
  340. Temp << "The required <socket> element was not present in the configuration file.";
  341. throw runtime_error(Temp.str());
  342. }
  343. break;
  344. default:
  345. {
  346. ostringstream Temp;
  347. Temp << "The type of the <socket> element configuration file is invalid. "
  348. "The type must by \"unix\" or \"inet\"";
  349. throw runtime_error(Temp.str());
  350. }
  351. }
  352. }
  353. SNFMilterSocketType SNFMilterContextPool::getSocketType() {
  354. return MilterSocketType;
  355. }
  356. string SNFMilterContextPool::getSocketPath() { return MilterSocketPath; }
  357. string SNFMilterContextPool::getSocketGroup() { return MilterSocketGroup; }
  358. string SNFMilterContextPool::getSocketIP() { return MilterSocketIP; }
  359. int SNFMilterContextPool::getSocketPort() { return MilterSocketPort; }
  360. SNFMilterContextPool::~SNFMilterContextPool() { // Dtor gracefully discards contexts.
  361. ScopeMutex ContextPoolLock(ContextAllocationControl); // Lock the context allocation system.
  362. myRulebase = 0; // Forget our rulebase. We're dead.
  363. for( // Loop through the context pool
  364. vector<SNFMilterContext*>::iterator iC = ContextPool.begin(); // and delete any contexts we have
  365. iC != ContextPool.end(); // allocated.
  366. iC++) { delete (*iC); }
  367. }
  368. SNFMilterContext* SNFMilterContextPool::grab() { // Get a context to use.
  369. ScopeMutex ContextPoolLock(ContextAllocationControl); // Lock the context allocation system.
  370. if(0 == myRulebase) return 0; // No contexts left if we're dead.
  371. if(1 > AvailableContexts.size()) { // If we need more contexts then
  372. SNFMilterContext* N = new SNFMilterContext(myRulebase); // Create a new context,
  373. ContextPool.push_back(N); // add it to the pool,
  374. AvailableContexts.give(N); // and make it available.
  375. }
  376. return AvailableContexts.take(); // Return the next avialable context.
  377. }
  378. void SNFMilterContextPool::drop(SNFMilterContext* E) { // Drop a context after use.
  379. // Update context state.
  380. E->State = SNFMilterContext::Pooled;
  381. AvailableContexts.give(E); // Make this context available.
  382. }
  383. bool SNFMilterContextPool::allUnused() {
  384. return (AvailableContexts.size() == ContextPool.size());
  385. }
  386. void SNFMilterContextPool::logThisError(string ContextName, int Code, string Text) {
  387. myRulebase->logThisError(ContextName, Code, Text);
  388. }
  389. void SNFMilterContextPool::logThisInfo(string ContextName, int Code, string Text) {
  390. myRulebase->logThisInfo(ContextName, Code, Text);
  391. }
  392. // End of configuration setup and engine and context interface components
  393. ////////////////////////////////////////////////////////////////////////////////
  394. ////////////////////////////////////////////////////////////////////////////////
  395. // SNFMilter callback definitions, constants, and global data.
  396. extern "C" {
  397. // Connection callback.
  398. //
  399. // This callback is invoked when a new connection is made to the
  400. // MTA. It obtains an available connection context object if one
  401. // hasn't already been assigned, and saves the IP address and name
  402. // of the connecting MTA. Next, it performs an IP scan, and
  403. // returns the appropriate response.
  404. //
  405. // Returns: SMFIS_CONTINUE, SMFIS_ACCEPT, SMFIS_TEMPFAIL, or
  406. // SMFIS_REJECT according to the following mapping:
  407. //
  408. // IPScanResult return mlfi_connect return
  409. //
  410. // Quarantine, Discard, Error FailSafeMilterResponse
  411. //
  412. // Anything else SNFMilterContext::smfisReturn(IPScanResult)
  413. //
  414. sfsistat
  415. mlfi_connect(SMFICTX *Ctx, char *HostName, _SOCK_ADDR *HostAddr)
  416. {
  417. const string ContextName = PACKAGE_NAME "::mlfi_connect";
  418. int ErrorCode = 1;
  419. int InfoCode = 1;
  420. sfsistat CallbackResult = FailSafeMilterResponse;
  421. try {
  422. SNFMilterContext *Context = assignContextToCtx(Ctx); // Get the existing context object,
  423. // or assign a new context object.
  424. Context->State = SNFMilterContext::Connect; // Update context state.
  425. sockaddr_in *SaIn = (sockaddr_in *) HostAddr; // Fetch the IP address.
  426. Context->ConnectionData.HostName = HostName; // Load the info.
  427. if (0 == SaIn) { // If HostAddr is 0...
  428. Context->ConnectionData.HostIP = "127.0.0.1"; // Set to a valid value.
  429. } else {
  430. Context->ConnectionData.HostIP = ntohl(SaIn->sin_addr.s_addr);
  431. }
  432. if (MilterDebugMode) {
  433. ostringstream Temp;
  434. Temp << "Connect from " << Context->ConnectionData.HostName << " ("
  435. << (string) Context->ConnectionData.HostIP << ").";
  436. logInfo(ContextName, InfoCode, Temp.str());
  437. }
  438. if (0 == SaIn) { // If HostAddr is 0, don't do a scan.
  439. return FailSafeMilterResponse;
  440. }
  441. SNFMilterAction IpScanResult; // Perform IP scan.
  442. IpScanResult = Context->milterEngine.scanIP(Context->ConnectionData.HostIP);
  443. if (MilterDebugMode) {
  444. ostringstream Temp;
  445. Temp << "IP scan result for connection from "
  446. << Context->ConnectionData.HostName << " ("
  447. << (string) Context->ConnectionData.HostIP << "): " << IpScanResult << ".";
  448. logInfo(ContextName, InfoCode, Temp.str());
  449. }
  450. if ( (Error == IpScanResult) || // Check for error
  451. (Quarantine == IpScanResult) ||
  452. (Discard == IpScanResult) ) {
  453. std::ostringstream Temp; // Illegal result.
  454. Temp << "Illegal result from IP scan for "
  455. << (string) Context->ConnectionData.HostIP
  456. << ": " << IpScanResult;
  457. throw std::runtime_error(Temp.str());
  458. }
  459. CallbackResult = Context->smfisReturn(IpScanResult); // Load return value.
  460. } catch (exception &E) {
  461. logError(ContextName, ErrorCode, E.what());
  462. } catch (...) {
  463. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  464. }
  465. return CallbackResult;
  466. }
  467. //
  468. // HELO callback.
  469. //
  470. // This callback is invoked when the connecting MTA sends a HELO
  471. // message. It saves the argument of the HELO command in the
  472. // connection context object.
  473. //
  474. // Returns: SMFIS_CONTINUE if no error, FailSafeMilterResponse
  475. // otherwise.
  476. //
  477. sfsistat
  478. mlfi_helo(SMFICTX *Ctx, char *heloHost)
  479. {
  480. const string ContextName = PACKAGE_NAME "::mlfi_helo";
  481. int ErrorCode = 1;
  482. int InfoCode = 1;
  483. sfsistat CallbackResult = FailSafeMilterResponse;
  484. try {
  485. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  486. Context->State = SNFMilterContext::Helo; // Update context state.
  487. Context->ConnectionData.HostHelo = heloHost; // Save the helo host name.
  488. if (MilterDebugMode) {
  489. ostringstream Temp;
  490. Temp << "HELO " << Context->ConnectionData.HostHelo << " from "
  491. << Context->ConnectionData.HostName << " ("
  492. << (string) Context->ConnectionData.HostIP << ").";
  493. logInfo(ContextName, InfoCode, Temp.str());
  494. }
  495. CallbackResult = SMFIS_CONTINUE; // Load return value.
  496. } catch (exception &E) {
  497. logError(ContextName, ErrorCode, E.what());
  498. } catch (...) {
  499. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  500. }
  501. return CallbackResult;
  502. }
  503. //
  504. // envfrom callback.
  505. //
  506. // This callback is invoked to process the envelope from line of the
  507. // mail message. It clears the message buffer, and adds the local
  508. // received header to the message buffer to scan. The local received
  509. // header is added to the email message in mlfi_eom.
  510. //
  511. // Returns: SMFIS_CONTINUE if no error, FailSafeMilterResponse
  512. // otherwise.
  513. //
  514. sfsistat
  515. mlfi_envfrom(SMFICTX *Ctx, char **argv)
  516. {
  517. const string ContextName = PACKAGE_NAME "::mlfi_envfrom";
  518. int ErrorCode = 1;
  519. int InfoCode = 1;
  520. sfsistat CallbackResult = FailSafeMilterResponse;
  521. try {
  522. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  523. Context->State = SNFMilterContext::EnvFrom; // Update context state.
  524. Context->MessageData.clear(); // This is the beginning of a new message.
  525. // Clear data from any previous message.
  526. if (MilterDebugMode) {
  527. Context->MessageData.SenderAddress = argv[0];
  528. ostringstream Temp;
  529. Temp << "Processing sender address " << Context->MessageData.SenderAddress
  530. << " (connection from " << Context->ConnectionData.HostName << " ("
  531. << (string) Context->ConnectionData.HostIP << ")).\n";
  532. logInfo(ContextName, InfoCode, Temp.str());
  533. }
  534. CallbackResult = SMFIS_CONTINUE; // Load return value.
  535. } catch (exception &E) {
  536. logError(ContextName, ErrorCode, E.what());
  537. } catch (...) {
  538. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  539. }
  540. return CallbackResult;
  541. }
  542. //
  543. // envrcpt callback.
  544. //
  545. // This callback is invoked to process the envelope receipt line of
  546. // the mail message.
  547. //
  548. // Returns: SMFIS_CONTINUE if no error, FailSafeMilterResponse
  549. // otherwise.
  550. //
  551. sfsistat
  552. mlfi_envrcpt(SMFICTX *Ctx, char **argv)
  553. {
  554. const string ContextName = PACKAGE_NAME "::mlfi_envrcpt";
  555. int ErrorCode = 1;
  556. int InfoCode = 1;
  557. sfsistat CallbackResult = FailSafeMilterResponse;
  558. try {
  559. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  560. // Update context state.
  561. Context->State = SNFMilterContext::EnvRcpt;
  562. if (MilterDebugMode) {
  563. ostringstream Temp;
  564. Temp << "Processing recipient " << argv[0] << " for message from "
  565. << Context->MessageData.SenderAddress
  566. << " (connection from " << Context->ConnectionData.HostName << " ("
  567. << (string) Context->ConnectionData.HostIP << ")).";
  568. logInfo(ContextName, InfoCode, Temp.str());
  569. }
  570. CallbackResult = SMFIS_CONTINUE; // Load return value.
  571. } catch (exception &E) {
  572. logError(ContextName, ErrorCode, E.what());
  573. } catch (...) {
  574. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  575. }
  576. return CallbackResult;
  577. }
  578. //
  579. // header callback.
  580. //
  581. // This callback is invoked to process the a header line of the mail
  582. // message. It writes the header line + SMTPENDL to the message buffer
  583. // that is scanned.
  584. //
  585. // Returns: SMFIS_CONTINUE if no error, FailSafeMilterResponse
  586. // otherwise.
  587. //
  588. sfsistat
  589. mlfi_header(SMFICTX *Ctx, char *headerf, char *headerv)
  590. {
  591. const string ContextName = PACKAGE_NAME "::mlfi_header";
  592. int ErrorCode = 1;
  593. int InfoCode = 1;
  594. sfsistat CallbackResult = FailSafeMilterResponse;
  595. try {
  596. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  597. Context->State = SNFMilterContext::Header; // Update context state.
  598. if (MilterDebugMode) {
  599. ostringstream Temp;
  600. Temp << "Processing header '" << headerf << ": " << headerv
  601. << "' for message from "
  602. << Context->MessageData.SenderAddress
  603. << " (connection from " << Context->ConnectionData.HostName << " ("
  604. << (string) Context->ConnectionData.HostIP << ")).";
  605. logInfo(ContextName, InfoCode, Temp.str());
  606. }
  607. Context->MessageData.MessageBuffer += headerf; // Add the header.
  608. Context->MessageData.MessageBuffer += ": ";
  609. Context->MessageData.MessageBuffer += headerv;
  610. Context->MessageData.MessageBuffer += SMTPENDL;
  611. CallbackResult = SMFIS_CONTINUE; // Load return value.
  612. } catch (exception &E) {
  613. logError(ContextName, ErrorCode, E.what());
  614. } catch (...) {
  615. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  616. }
  617. return CallbackResult;
  618. }
  619. //
  620. // End of header callback.
  621. //
  622. // This callback is invoked after the last header of the mail
  623. // message is sent. It writes SMTPENDL SMTPENDL to the message
  624. // buffer that is scanned.
  625. //
  626. // Returns: SMFIS_CONTINUE if no error, FailSafeMilterResponse
  627. // otherwise.
  628. //
  629. sfsistat
  630. mlfi_eoh(SMFICTX *Ctx)
  631. {
  632. const string ContextName = PACKAGE_NAME "::mlfi_eoh";
  633. int ErrorCode = 1;
  634. int InfoCode = 1;
  635. sfsistat CallbackResult = FailSafeMilterResponse;
  636. try {
  637. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  638. Context->State = SNFMilterContext::EOH; // Update context state.
  639. Context->MessageData.MessageBuffer += SMTPENDL + SMTPENDL; // Add the blank lines..
  640. if (MilterDebugMode) {
  641. ostringstream Temp;
  642. Temp << "All headers received for message from "
  643. << Context->MessageData.SenderAddress
  644. << " (connection from " << Context->ConnectionData.HostName << " ("
  645. << (string) Context->ConnectionData.HostIP << ")). Message buffer--\n'"
  646. << Context->MessageData.MessageBuffer << "'.";
  647. logInfo(ContextName, InfoCode, Temp.str());
  648. }
  649. CallbackResult = SMFIS_CONTINUE; // Load return value.
  650. } catch (exception &E) {
  651. logError(ContextName, ErrorCode, E.what());
  652. } catch (...) {
  653. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  654. }
  655. return CallbackResult;
  656. }
  657. //
  658. // message body callback.
  659. //
  660. // This callback is invoked zero or more times to send the body of the
  661. // mail message is sent. It writes the body to the message buffer that
  662. // is scanned.
  663. //
  664. // Returns: SMFIS_CONTINUE if more of the message body is needed,
  665. // SkipReturn if more of the message body is not needed, or
  666. // FailSafeMilterResponse if an error occurs. Context is the
  667. // connection context object.
  668. //
  669. sfsistat
  670. mlfi_body(SMFICTX *Ctx, unsigned char *Bodyp, size_t Bodylen)
  671. {
  672. const string ContextName = PACKAGE_NAME "::mlfi_body";
  673. int ErrorCode = 1;
  674. int InfoCode = 1;
  675. sfsistat CallbackResult = FailSafeMilterResponse;
  676. try {
  677. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  678. Context->State = SNFMilterContext::Body; // Update context state.
  679. if (Context->MessageData.MessageBuffer.size() >= // Return if there is enough in the
  680. MailBufferReserveSize) { // message buffer.
  681. return SkipReturn;
  682. }
  683. if (Context->MessageData.MessageBuffer.size() < // Do we need to copy this?
  684. MailBufferReserveSize) {
  685. string::size_type NCharToTransfer = MailBufferReserveSize - // Yes. How much more?
  686. Context->MessageData.MessageBuffer.size();
  687. if (NCharToTransfer > Bodylen) { // Don't transfer more characters
  688. // than are available.
  689. NCharToTransfer = Bodylen;
  690. }
  691. Context->MessageData.MessageBuffer.append((const char *) Bodyp, // Append the message.
  692. NCharToTransfer);
  693. if (MilterDebugMode) {
  694. ostringstream Temp;
  695. Temp << "Appended " << NCharToTransfer << " bytes to "
  696. << "message from " << Context->MessageData.SenderAddress
  697. << " (connection from " << Context->ConnectionData.HostName << " ("
  698. << (string) Context->ConnectionData.HostIP << ")). Message length: "
  699. << Context->MessageData.MessageBuffer.size() << ".";
  700. logInfo(ContextName, InfoCode, Temp.str());
  701. }
  702. } else {
  703. if (MilterDebugMode) {
  704. ostringstream Temp;
  705. Temp << "Discarded " << Bodylen << " bytes "
  706. << "message from " << Context->MessageData.SenderAddress
  707. << " (connection from " << Context->ConnectionData.HostName << " ("
  708. << (string) Context->ConnectionData.HostIP << ")) because "
  709. << MailBufferReserveSize << " bytes have already been "
  710. << "transferred. Message length: "
  711. << Context->MessageData.MessageBuffer.size() << ".";
  712. logInfo(ContextName, InfoCode, Temp.str());
  713. }
  714. }
  715. CallbackResult = SMFIS_CONTINUE; // Load return value.
  716. } catch (exception &E) {
  717. logError(ContextName, ErrorCode, E.what());
  718. } catch (...) {
  719. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  720. }
  721. return CallbackResult;
  722. }
  723. //
  724. // End-Of-Message callback.
  725. //
  726. // This callback is invoked to when the entire message has been sent
  727. // to SNFMilter. It adds the local received header to the email
  728. // message, and then scans the message body. If the scan result
  729. // indicates that the message is to be quarantined, then the message
  730. // is set to be quarantined (using smfi_quarantine).
  731. //
  732. // Returns: SMFIS_CONTINUE, SMFIS_ACCEPT, SMFIS_TEMPFAIL, or
  733. // SMFIS_DISCARD, SMFIS_REJECT, or FailSafeMilterResponse
  734. // according to the following mapping:
  735. //
  736. // MessageScan return mlfi_connect return
  737. //
  738. // Error FailSafeMilterResponse
  739. //
  740. // Anything else SNFMilterContext::smfisReturn(IPScanResult)
  741. //
  742. // Side effect: If the MessageScan result is Quarantine, the
  743. // message is quarantined using smfi_quarantine().
  744. //
  745. sfsistat
  746. mlfi_eom(SMFICTX *Ctx)
  747. {
  748. const string ContextName = PACKAGE_NAME "::mlfi_eom";
  749. int ErrorCode = 1;
  750. int InfoCode = 1;
  751. sfsistat CallbackResult = FailSafeMilterResponse;
  752. try {
  753. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  754. Context->State = SNFMilterContext::EOM; // Update context state.
  755. if (MilterDebugMode) {
  756. ostringstream Temp;
  757. Temp << "End of message from " << Context->MessageData.SenderAddress
  758. << " (connection from " << Context->ConnectionData.HostName << " ("
  759. << (string) Context->ConnectionData.HostIP << ")).";
  760. logInfo(ContextName, InfoCode, Temp.str());
  761. }
  762. if (PrependLocalReceivedHeader) {
  763. Context->MessageData.MessageBuffer.
  764. insert(0, Context->getLocalReceivedHeader() + SMTPENDL); // Prepend local received header line
  765. // to the message buffer.
  766. }
  767. SNFMilterAction MsgScanResult; // Perform scan.
  768. MsgScanResult =
  769. Context->milterEngine.scanMessage((unsigned char *) Context->MessageData.MessageBuffer.c_str(),
  770. Context->MessageData.MessageBuffer.size());
  771. if (MilterDebugMode) {
  772. ostringstream Temp;
  773. Temp << "Message scan result for message from " << Context->MessageData.SenderAddress
  774. << " (connection from " << Context->ConnectionData.HostName << " ("
  775. << (string) Context->ConnectionData.HostIP << ")): " << MsgScanResult << ".";
  776. logInfo(ContextName, InfoCode, Temp.str());
  777. }
  778. if (Error == MsgScanResult) { // Check for scan error
  779. // Illegal result.
  780. std::ostringstream Temp;
  781. Temp << "Illegal message scan result for message from "
  782. << Context->MessageData.SenderAddress
  783. << " (connection from " << Context->ConnectionData.HostName << " ("
  784. << (string) Context->ConnectionData.HostIP << ")): " << MsgScanResult;
  785. throw std::runtime_error(Temp.str());
  786. }
  787. string XHeaders = Context->milterEngine.XHeaders(); // Fetch X-headers to submit.
  788. MailHeaders MailHeadersParse; // Object to parse X-headers.
  789. MailHeadersParse.loadHeaders(XHeaders); // Load the headers to be parsed.
  790. string HeaderName; // Name of X-header.
  791. string HeaderBody; // Body of X-header, formatted for libmilter.
  792. while (MailHeadersParse.getNameBody(&HeaderName, &HeaderBody)) { // While there is an X-Header...
  793. if (MilterDebugMode) {
  794. ostringstream Temp;
  795. Temp << "Processed X-Header for message from " << Context->MessageData.SenderAddress
  796. << " (connection from " << Context->ConnectionData.HostName << " ("
  797. << (string) Context->ConnectionData.HostIP << ")). X-Header name: '"
  798. << HeaderName << "'. X-Header body: '" << HeaderBody << "'.";
  799. logInfo(ContextName, InfoCode, Temp.str());
  800. }
  801. if (MI_SUCCESS != smfi_addheader(Ctx, // Add header to the email message.
  802. (char *) HeaderName.c_str(),
  803. (char *) HeaderBody.c_str())) {
  804. ostringstream Temp;
  805. Temp << "Error adding X-header to message from " << Context->MessageData.SenderAddress
  806. << " (connection from " << Context->ConnectionData.HostName << " ("
  807. << (string) Context->ConnectionData.HostIP
  808. << ")).\nX-Header name: '" << HeaderName << "'. X-Header body--\n'"
  809. << HeaderBody << "'.";
  810. logError(ContextName, 1, Temp.str());
  811. }
  812. }
  813. if (Quarantine == MsgScanResult) { // Quarantine the message?
  814. if (MilterDebugMode) {
  815. ostringstream Temp;
  816. Temp << "Quarantining message from " << Context->MessageData.SenderAddress
  817. << " (connection from " << Context->ConnectionData.HostName << " ("
  818. << (string) Context->ConnectionData.HostIP << ")).";
  819. logInfo(ContextName, InfoCode, Temp.str());
  820. }
  821. if (MI_SUCCESS != smfi_quarantine(Ctx,
  822. (char *) "Quarantined by " PACKAGE_NAME)) {
  823. ostringstream Temp;
  824. Temp << "Error quarantining message from "
  825. << Context->MessageData.SenderAddress
  826. << " (connection from " << Context->ConnectionData.HostName << " ("
  827. << (string) Context->ConnectionData.HostIP << ")).";
  828. logError(ContextName, 1, Temp.str());
  829. }
  830. return SMFIS_CONTINUE;
  831. }
  832. CallbackResult = Context->smfisReturn(MsgScanResult); // Load return value.
  833. } catch (exception &E) {
  834. logError(ContextName, ErrorCode, E.what());
  835. } catch (...) {
  836. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  837. }
  838. return CallbackResult;
  839. }
  840. //
  841. // Callback for aborting the message.
  842. //
  843. // This callback is invoked to when the processing of the current
  844. // message is to be aborted. It logs the abort as an info event,
  845. // clears the email message buffer, and sets the state to
  846. // connected.
  847. //
  848. // Returns: SMFIS_CONTINUE if no error, FailSafeMilterResponse
  849. // otherwise.
  850. //
  851. sfsistat
  852. mlfi_abort(SMFICTX *Ctx)
  853. {
  854. const string ContextName = PACKAGE_NAME "::mlfi_abort";
  855. int ErrorCode = 1;
  856. int InfoCode = 1;
  857. sfsistat CallbackResult = FailSafeMilterResponse;
  858. try {
  859. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  860. Context->State = SNFMilterContext::Connect; // Update context state.
  861. ostringstream Temp; // Log message.
  862. Temp << "Aborted processing of message from " << Context->MessageData.SenderAddress
  863. << " (connection from " << Context->ConnectionData.HostName << " ("
  864. << (string) Context->ConnectionData.HostIP << ")).";
  865. logInfo(ContextName, InfoCode, Temp.str());
  866. Context->MessageData.clear(); // Clear data for this message.
  867. CallbackResult = SMFIS_CONTINUE; // Load return value.
  868. } catch (exception &E) {
  869. logError(ContextName, ErrorCode, E.what());
  870. } catch (...) {
  871. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  872. }
  873. return CallbackResult;
  874. }
  875. //
  876. // Callback for closing the connection.
  877. //
  878. // This callback is invoked to when the connection with the remote MTA is closed.
  879. // It returns the connection context object to the pool.
  880. //
  881. // Returns: SMFIS_CONTINUE if no error, FailSafeMilterResponse
  882. // otherwise.
  883. //
  884. sfsistat
  885. mlfi_close(SMFICTX *Ctx)
  886. {
  887. const string ContextName = PACKAGE_NAME "::mlfi_close";
  888. int ErrorCode = 1;
  889. int InfoCode = 1;
  890. sfsistat CallbackResult = FailSafeMilterResponse;
  891. try {
  892. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  893. Context->State = SNFMilterContext::Close; // Update context state.
  894. if (MilterDebugMode) {
  895. ostringstream Temp;
  896. Temp << "Closing connection from "
  897. << Context->ConnectionData.HostName << " ("
  898. << (string) Context->ConnectionData.HostIP << ").";
  899. logInfo(ContextName, InfoCode, Temp.str());
  900. }
  901. MilterContexts->drop(Context); // Return the context object.
  902. smfi_setpriv(Ctx, 0);
  903. CallbackResult = SMFIS_CONTINUE; // Load return value.
  904. } catch (exception &E) {
  905. logError(ContextName, ErrorCode, E.what());
  906. } catch (...) {
  907. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  908. }
  909. return CallbackResult;
  910. }
  911. #ifdef NEW_LIBMILTER
  912. //
  913. // Callback for unknown SMTP command.
  914. //
  915. // This callback is invoked to when an unknown SMTP command is
  916. // received by the local MTA. The unknown command is logged.
  917. //
  918. // Returns: SMFIS_CONTINUE if no error, FailSafeMilterResponse
  919. // otherwise.
  920. //
  921. sfsistat
  922. mlfi_unknown(SMFICTX *Ctx, const char *Cmd)
  923. {
  924. const string ContextName = PACKAGE_NAME "::mlfi_unknown";
  925. int ErrorCode = 1;
  926. int InfoCode = 1;
  927. sfsistat CallbackResult = FailSafeMilterResponse;
  928. try {
  929. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  930. ostringstream Temp; // Log.
  931. Temp << "Unknown SMTP command from "
  932. << Context->ConnectionData.HostName << " ("
  933. << (string) Context->ConnectionData.HostIP << "): '"
  934. << *Cmd << "'";
  935. logInfo(ContextName, InfoCode, Temp.str());
  936. CallbackResult = SMFIS_CONTINUE; // Load return value.
  937. } catch (exception &E) {
  938. logError(ContextName, ErrorCode, E.what());
  939. } catch (...) {
  940. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  941. }
  942. return CallbackResult;
  943. }
  944. //
  945. // data callback.
  946. //
  947. // This callback is invoked when the connecting MTA sends a DATA
  948. // message.
  949. //
  950. // Returns: SMFIS_CONTINUE if no error, FailSafeMilterResponse
  951. // otherwise.
  952. //
  953. sfsistat
  954. mlfi_data(SMFICTX *Ctx)
  955. {
  956. const string ContextName = PACKAGE_NAME "::mlfi_data";
  957. int ErrorCode = 1;
  958. int InfoCode = 1;
  959. sfsistat CallbackResult = FailSafeMilterResponse;
  960. try {
  961. SNFMilterContext *Context = getContextFromCtx(Ctx); // Get the context object.
  962. Context->State = SNFMilterContext::Data; // Update context state.
  963. if (MilterDebugMode) {
  964. ostringstream Temp;
  965. Temp << "DATA for message from "
  966. << Context->MessageData.SenderAddress
  967. << " (connection from " << Context->ConnectionData.HostName << " ("
  968. << (string) Context->ConnectionData.HostIP << ")).";
  969. logInfo(ContextName, InfoCode, Temp.str());
  970. }
  971. CallbackResult = SMFIS_CONTINUE; // Load return value.
  972. } catch (exception &E) {
  973. logError(ContextName, ErrorCode, E.what());
  974. } catch (...) {
  975. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  976. }
  977. return CallbackResult;
  978. }
  979. //
  980. // Callback for negotiating the capabilities of the MTA.
  981. //
  982. // This callback is invoked at the start of each SMTP connection.
  983. // It obtains an available connection context object if one hasn't
  984. // already been assigned, checks whether the MTA can accept an
  985. // SMFIS_SKIP return, and configures the connection context object
  986. // to return an acceptable value.
  987. //
  988. // Returns: SMFIS_CONTINUE if no error, FailSafeMilterResponse
  989. // otherwise.
  990. //
  991. sfsistat
  992. mlfi_negotiate(SMFICTX *Ctx,
  993. unsigned long F0,
  994. unsigned long F1,
  995. unsigned long F2,
  996. unsigned long F3,
  997. unsigned long *PF0,
  998. unsigned long *PF1,
  999. unsigned long *PF2,
  1000. unsigned long *PF3)
  1001. {
  1002. const string ContextName = PACKAGE_NAME "::mlfi_negotiate";
  1003. int ErrorCode = 1;
  1004. int InfoCode = 1;
  1005. sfsistat CallbackResult = SMFIS_ALL_OPTS;
  1006. try {
  1007. bool AcceptsSkip = F1 & SMFIP_SKIP;
  1008. if (AcceptsSkip) { // MTA accepts SMFIS_SKIP return?
  1009. SkipReturn = SMFIS_SKIP; // Yes. Use SMFIS_SKIP.
  1010. } else {
  1011. SkipReturn = SMFIS_CONTINUE; // No. Use SMFIS_CONTINUE.
  1012. }
  1013. if (MilterDebugMode) {
  1014. ostringstream Temp; // Log message.
  1015. Temp << "MTA does " << (AcceptsSkip ? "" : "not ") << "accept SMFIS_SKIP.";
  1016. logInfo(ContextName, InfoCode, Temp.str());
  1017. }
  1018. CallbackResult = SMFIS_ALL_OPTS; // Load return value.
  1019. } catch (exception &E) {
  1020. logError(ContextName, ErrorCode, E.what());
  1021. } catch (...) {
  1022. logError(ContextName, ErrorCode, UnknownExceptionMessage);
  1023. }
  1024. return CallbackResult;
  1025. }
  1026. #endif
  1027. }
  1028. // End of SNFMilter callback definitions, constants, and global data.
  1029. ////////////////////////////////////////////////////////////////////////////////
  1030. ////////////////////////////////////////////////////////////////////////////////
  1031. // SNFMilter setup & run function.
  1032. // The runLibMilter function establishes the appropriate libmilter call backs and
  1033. // accepts calls from the MTA via libmilter until it is told to quit. When it
  1034. // is told to quit it gracefully closes down, reclaims any memory it allocated,
  1035. // and returns.
  1036. void runLibMilter(SNFMilterContextPool* Contexts, bool DebugMode) { // Run the milter 'til it's done.
  1037. MilterContexts = Contexts; // Save the pool of context objects.
  1038. MilterDebugMode = DebugMode; // Save the debug mode flag.
  1039. #if 0
  1040. if (MilterDebugMode) {
  1041. openlog(PACKAGE_NAME, LOG_PID | LOG_PERROR, LOG_MAIL); // Initialize system logging to log
  1042. // messages to mail file.
  1043. }
  1044. #endif
  1045. struct smfiDesc smfilter = { // Load structure containing callbacks.
  1046. (char *) PACKAGE_NAME, // Filter name.
  1047. SMFI_VERSION, // Version code -- do not change.
  1048. SMFIF_ADDHDRS | SMFIF_QUARANTINE, // Flags.
  1049. mlfi_connect, // Connection info callback.
  1050. mlfi_helo, // SMTP HELO command callback.
  1051. mlfi_envfrom, // Envelope sender callback.
  1052. mlfi_envrcpt, // Envelope recipient callback.
  1053. mlfi_header, // Header callback.
  1054. mlfi_eoh, // End of headers callback.
  1055. mlfi_body, // Body block callback.
  1056. mlfi_eom, // End of message callback.
  1057. mlfi_abort, // Message abort callback.
  1058. mlfi_close // Connection closed callback.
  1059. #ifdef NEW_LIBMILTER
  1060. ,
  1061. mlfi_unknown, // Unknown SMTP command callback.
  1062. mlfi_data, // DATA ccallback.
  1063. mlfi_negotiate // Negotiation at the start of each SMTP
  1064. #endif
  1065. // connection callback.
  1066. };
  1067. string MilterConnSpec;
  1068. switch (Contexts->getSocketType()) { // Configure the connection.
  1069. case UNIXMilterSocket:
  1070. MilterConnSpec = "unix:" + Contexts->getSocketPath(); // Generate the connection spec.
  1071. break;
  1072. case TCPMilterSocket:
  1073. {
  1074. ostringstream Temp;
  1075. Temp << "inet:" << Contexts->getSocketPort() << "@" // Generate the connection spec.
  1076. << Contexts->getSocketIP();
  1077. MilterConnSpec = Temp.str();
  1078. }
  1079. break;
  1080. default:
  1081. {
  1082. ostringstream Temp;
  1083. Temp << PACKAGE " internal error: Invalid socket type from SNFMilterContextPool.";
  1084. throw logic_error(Temp.str());
  1085. }
  1086. }
  1087. if (MI_FAILURE == smfi_setconn(const_cast<char *>(MilterConnSpec.c_str()))) {
  1088. ostringstream Temp;
  1089. Temp << "smfi_setconn failed with input \"" << MilterConnSpec << "\"";
  1090. throw std::runtime_error(Temp.str());
  1091. }
  1092. if (MI_FAILURE == smfi_register(smfilter)) { // Register the callbacks.
  1093. string msg = "smfi_register failed";
  1094. throw std::runtime_error(msg);
  1095. }
  1096. if (UNIXMilterSocket == Contexts->getSocketType()) {
  1097. if (MI_FAILURE == smfi_opensocket(true)) { // Create the named pipe.
  1098. ostringstream Temp;
  1099. Temp << "smfi_opensocket failed for \"" << MilterConnSpec << "\"";
  1100. throw std::runtime_error(Temp.str());
  1101. }
  1102. string MilterConnPath = Contexts->getSocketPath();
  1103. if (chmod(MilterConnPath.c_str(), // Set permissions.
  1104. S_IRUSR | S_IWUSR |
  1105. S_IRGRP | S_IWGRP) != 0) {
  1106. ostringstream Temp;
  1107. Temp << "Error setting permissions of " << MilterConnPath << ": "
  1108. << strerror(errno);
  1109. throw runtime_error(Temp.str());
  1110. }
  1111. string GroupName = Contexts->getSocketGroup();
  1112. if (0 != GroupName.size()) { // Was a group specified?
  1113. struct group *Group = getgrnam(GroupName.c_str()); // Get the ID of the group.
  1114. errno = 0;
  1115. if (NULL == Group) {
  1116. ostringstream Temp;
  1117. if (0 != errno) { // Error?
  1118. Temp << "Error obtaining the group ID of " << GroupName << ": "
  1119. << strerror(errno);
  1120. } else { // Group not found.
  1121. Temp << "Error obtaining the group ID of " << GroupName << ": "
  1122. << "No such group";
  1123. }
  1124. throw runtime_error(Temp.str());
  1125. }
  1126. if (chown(MilterConnPath.c_str(), // Set group.
  1127. -1,
  1128. Group->gr_gid) != 0) {
  1129. ostringstream Temp;
  1130. Temp << "Error setting group of " << MilterConnPath << " to "
  1131. << Group->gr_name << ": " << strerror(errno);
  1132. throw runtime_error(Temp.str());
  1133. }
  1134. }
  1135. }
  1136. if (MI_FAILURE == smfi_main()) { // Hand control to libmilter
  1137. string msg = "smfi_main failed";
  1138. throw std::runtime_error(msg);
  1139. }
  1140. const string ContextName = "--EXITING--";
  1141. int ErrorCode = 1;
  1142. int InfoCode = 1;
  1143. logInfo(ContextName, InfoCode, "Shutdown command received. Waiting for message processing to complete...");
  1144. Sleeper WaitATic;
  1145. try {
  1146. WaitATic.setMillisecondsToSleep(ShutdownWaitPeriod_ms); // Learn to wait.
  1147. }
  1148. catch(...) {
  1149. ostringstream Temp;
  1150. Temp << "Invalid value for ShutdownWaitPeriod_ms: " << ShutdownWaitPeriod_ms << ".";
  1151. throw out_of_range(Temp.str());
  1152. }
  1153. int iPeriod = 0; // Number of periods waited.
  1154. while (!MilterContexts->allUnused() && iPeriod < ShutdownPeriods) {
  1155. iPeriod++;
  1156. WaitATic(); // Wait a period.
  1157. }
  1158. if (!MilterContexts->allUnused()) {
  1159. logError(ContextName, ErrorCode, "Not all messages finished processing.");
  1160. }
  1161. logInfo(ContextName, InfoCode, "Exiting");
  1162. WaitATic(); // Wait for messages to be logged.
  1163. MilterContexts = 0; // Turn off.
  1164. }