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

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