Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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