選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

SNFMilter.cpp.new 59KB

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