You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PostfixIntegrate.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. // /file PostfixIntegrate.cpp
  2. //
  3. // Copyright (C) 2011, ARM Research Labs, LLC.
  4. // See www.armresearch.com for the copyright terms.
  5. //
  6. // This file contains the functions for PostfixIntegrate.
  7. //
  8. // $Id$
  9. //
  10. ///////////////////////////////////////////////////////////////////////////////////////////////////
  11. #include <cstdlib>
  12. #include <cerrno>
  13. #include <cstring>
  14. #include <iostream>
  15. #include <exception>
  16. #include <stdexcept>
  17. #include <sstream>
  18. #include <fstream>
  19. #include "PostfixIntegrate.hpp"
  20. #include "PostfixMilterConf.hpp"
  21. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  22. // Configuration. ////////////////////////////////////////////////////////////////////////////////////////
  23. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  24. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  25. // End of configuration. /////////////////////////////////////////////////////////////////////////////////
  26. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  27. void
  28. PostfixIntegrate::SetOperatingSystem(std::string OperatingSystemType) {
  29. MtaIsRunningCommand = "ps axl | grep -v grep | grep -q 'postfix/master'";
  30. if ("OpenBSD" == OperatingSystemType) {
  31. PostfixDefaultIsChrooted = true;
  32. PostfixSocketSpec = "unix:/snf-milter/socket";
  33. PostfixMainCfPath = "/etc/postfix/main.cf";
  34. PostfixMasterCfPath = "/etc/postfix/master.cf";
  35. ReloadMtaCommand = "/usr/local/sbin/postfix reload";
  36. } else if ("FreeBSD" == OperatingSystemType) {
  37. PostfixDefaultIsChrooted = false;
  38. PostfixSocketSpec = "unix:/var/snf-milter/socket";
  39. PostfixMainCfPath = "/usr/local/etc/postfix/main.cf";
  40. PostfixMasterCfPath = "/usr/local/etc/postfix/master.cf";
  41. ReloadMtaCommand = "/usr/local/sbin/postfix reload";
  42. } else if ("Ubuntu" == OperatingSystemType) {
  43. PostfixDefaultIsChrooted = true;
  44. PostfixSocketSpec = "unix:/snf-milter/socket";
  45. PostfixMainCfPath = "/etc/postfix/main.cf";
  46. PostfixMasterCfPath = "/etc/postfix/master.cf";
  47. ReloadMtaCommand = "/usr/sbin/postfix reload";
  48. } else if ("RedHat" == OperatingSystemType) {
  49. PostfixDefaultIsChrooted = false;
  50. PostfixSocketSpec = "unix:/var/snf-milter/socket";
  51. PostfixMainCfPath = "/etc/postfix/main.cf";
  52. PostfixMasterCfPath = "/etc/postfix/master.cf";
  53. ReloadMtaCommand = "/usr/sbin/postfix reload";
  54. } else if ("Suse" == OperatingSystemType) {
  55. PostfixDefaultIsChrooted = false;
  56. PostfixSocketSpec = "unix:/var/snf-milter/socket";
  57. PostfixMainCfPath = "/etc/postfix/main.cf";
  58. PostfixMasterCfPath = "/etc/postfix/master.cf";
  59. ReloadMtaCommand = "/usr/sbin/postfix reload";
  60. } else {
  61. std::ostringstream Temp;
  62. Temp << "***Error from PostfixIntegrate::SetOperatingSystem: Invalid value of OperatingSystemType: "
  63. << OperatingSystemType;
  64. throw std::runtime_error(Temp.str());
  65. }
  66. }
  67. void
  68. PostfixIntegrate::Integrate(FileBackup *SaveFile) {
  69. if (IsIntegrated()) {
  70. return;
  71. }
  72. // Check whether the chroot configuration is as expected.
  73. bool IsChrooted;
  74. IsChrooted = MtaConfigurationIsChrooted();
  75. if (IsChrooted != PostfixDefaultIsChrooted) {
  76. std::string Temp;
  77. Temp = "Error--postfix must be configured to run ";
  78. Temp += (PostfixDefaultIsChrooted ? "" : "not ");
  79. Temp += "chrooted, which is the default for this operating system. ";
  80. Temp += "postfix was detected to be configured to run ";
  81. Temp += (IsChrooted ? "" : "not ");
  82. Temp += "chrooted.";
  83. Temp += strerror(errno);
  84. throw std::runtime_error(Temp);
  85. }
  86. std::ifstream Input;
  87. if (Verbose()) {
  88. std::cout << "Integrate with postfix...\n";
  89. }
  90. if (!Explain()) {
  91. SaveFile->CreateBackupFile(PostfixMainCfPath); // Save any existing file.
  92. Input.open(PostfixMainCfPath.c_str()); // Read the contents.
  93. if (!Input) {
  94. std::string Temp;
  95. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  96. Temp += " for reading: ";
  97. Temp += strerror(errno);
  98. throw std::runtime_error(Temp);
  99. }
  100. std::string Content;
  101. std::string Line;
  102. bool ModifiedLine = false;
  103. PostfixMilterConf MilterConf(PostfixSocketSpec); // Object to update the config line.
  104. while (getline(Input, Line)) {
  105. MilterConf.ConfLine(Line); // Load the object with the line.
  106. if (MilterConf.IsMilterLine() && !ModifiedLine) { // Check for milter integration line.
  107. // Ignore subsequence integration lines.
  108. MilterConf.AddIntegration(); // Found milter line. Add integration.
  109. if (Verbose()) {
  110. std::cout << " Replace '" << Line << "' with '"
  111. << MilterConf.ConfLine() << "'...\n";
  112. }
  113. Line = MilterConf.ConfLine(); // Copy updated line.
  114. ModifiedLine = true;
  115. }
  116. Content += Line + "\n"; // Copy this line.
  117. }
  118. if (!ModifiedLine) {
  119. MilterConf.ConfLine("");
  120. MilterConf.AddIntegration();
  121. if (Verbose()) {
  122. std::cout << " Add '" << MilterConf.ConfLine() << "'...\n";
  123. }
  124. Content += MilterConf.ConfLine() + "\n";
  125. }
  126. if (!Input.eof()) { // Should be at end-of-file.
  127. std::string Temp;
  128. Temp = "Error reading the postfix configuration file " + PostfixMainCfPath;
  129. Temp += ": ";
  130. Temp += strerror(errno);
  131. throw std::runtime_error(Temp);
  132. }
  133. Input.close();
  134. if (Input.bad()) {
  135. std::string Temp;
  136. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  137. Temp += " after reading: ";
  138. Temp += strerror(errno);
  139. throw std::runtime_error(Temp);
  140. }
  141. if (!Explain()) {
  142. std::ofstream Output; // Write the updated contents.
  143. Output.open(PostfixMainCfPath.c_str(), std::ios::trunc);
  144. if (!Output) {
  145. std::string Temp;
  146. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  147. Temp += " for writing: ";
  148. Temp += strerror(errno);
  149. throw std::runtime_error(Temp);
  150. }
  151. Output << Content;
  152. if (!Output) {
  153. std::string Temp;
  154. Temp = "Error writing the postfix configuration file " + PostfixMainCfPath;
  155. Temp += ": ";
  156. Temp += strerror(errno);
  157. throw std::runtime_error(Temp);
  158. }
  159. Output.close();
  160. if (!Output) {
  161. std::string Temp;
  162. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  163. Temp += " after writing: ";
  164. Temp += strerror(errno);
  165. throw std::runtime_error(Temp);
  166. }
  167. }
  168. }
  169. OutputVerboseEnd();
  170. if (!ReloadMta()) {
  171. std::cerr << "Unable to reload the postfix configuration. Please run "
  172. << "'postfix reload' for the integration with SNFMilter to take effect.";
  173. }
  174. }
  175. void
  176. PostfixIntegrate::Unintegrate(FileBackup *SaveFile) {
  177. if (!IsIntegrated()) {
  178. return;
  179. }
  180. std::ifstream Input;
  181. if (Verbose()) {
  182. std::cout << "Remove integration in postfix file " << PostfixMainCfPath << "--\n";
  183. }
  184. if (!Explain()) {
  185. SaveFile->CreateBackupFile(PostfixMainCfPath); // Save any existing file.
  186. Input.open(PostfixMainCfPath.c_str()); // Read the contents.
  187. if (!Input) {
  188. std::string Temp;
  189. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  190. Temp += " for reading: ";
  191. Temp += strerror(errno);
  192. throw std::runtime_error(Temp);
  193. }
  194. std::string Content;
  195. std::string Line;
  196. PostfixMilterConf MilterConf(PostfixSocketSpec); // Object to update the config line.
  197. while (getline(Input, Line)) {
  198. MilterConf.ConfLine(Line); // Load the object with the line.
  199. if (MilterConf.IsIntegrated()) { // Check for integration.
  200. MilterConf.RemoveIntegration(); // Integrated. Remove the milter spec.
  201. if (Verbose()) {
  202. std::cout << " Replace '" << Line << "' with '"
  203. << MilterConf.ConfLine() << "'...\n";
  204. }
  205. Content += MilterConf.ConfLine(); // Copy updated line.
  206. if (MilterConf.ConfLine() != "") {
  207. Content += "\n";
  208. }
  209. continue;
  210. }
  211. Content += Line + "\n"; // Copy this line.
  212. }
  213. if (!Input.eof()) { // Should be at end-of-file.
  214. std::string Temp;
  215. Temp = "Error reading the postfix configuration file " + PostfixMainCfPath;
  216. Temp += ": ";
  217. Temp += strerror(errno);
  218. throw std::runtime_error(Temp);
  219. }
  220. Input.close();
  221. if (Input.bad()) {
  222. std::string Temp;
  223. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  224. Temp += " after reading: ";
  225. Temp += strerror(errno);
  226. throw std::runtime_error(Temp);
  227. }
  228. if (!Explain()) {
  229. std::ofstream Output; // Write the updated contents.
  230. Output.open(PostfixMainCfPath.c_str(), std::ios::trunc);
  231. if (!Output) {
  232. std::string Temp;
  233. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  234. Temp += " for writing: ";
  235. Temp += strerror(errno);
  236. throw std::runtime_error(Temp);
  237. }
  238. Output << Content;
  239. if (!Output) {
  240. std::string Temp;
  241. Temp = "Error writing the postfix configuration file " + PostfixMainCfPath;
  242. Temp += ": ";
  243. Temp += strerror(errno);
  244. throw std::runtime_error(Temp);
  245. }
  246. Output.close();
  247. if (!Output) {
  248. std::string Temp;
  249. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  250. Temp += " after writing: ";
  251. Temp += strerror(errno);
  252. throw std::runtime_error(Temp);
  253. }
  254. }
  255. }
  256. OutputVerboseEnd();
  257. if (!ReloadMta()) {
  258. std::cerr << "Unable to reload the postfix configuration. Please run "
  259. << "'postfix reload' for the integration with SNFMilter to take effect.";
  260. }
  261. }
  262. bool
  263. PostfixIntegrate::MtaIsRunningDetected() {
  264. if (Verbose()) {
  265. std::cout << "Checking whether postfix is detected to be running...";
  266. }
  267. bool IsRunningDetected;
  268. IsRunningDetected = (std::system(MtaIsRunningCommand.c_str()) == 0);
  269. if (Verbose()) {
  270. std::cout << (IsRunningDetected ? "yes..." : "no...");
  271. }
  272. OutputVerboseEnd();
  273. return IsRunningDetected;
  274. }
  275. bool
  276. PostfixIntegrate::ReloadMta() {
  277. if (!MtaIsRunningDetected()) {
  278. return true;
  279. }
  280. if (Verbose()) {
  281. std::cout << "Reloading postfix...\n";
  282. std::cout.flush();
  283. }
  284. bool Succeeded;
  285. if (!Explain()) {
  286. Succeeded = (std::system(ReloadMtaCommand.c_str()) == 0);
  287. if (Verbose()) {
  288. std::cout << (Succeeded ? "succeeded..." : "failed...");
  289. }
  290. }
  291. OutputVerboseEnd();
  292. return Succeeded;
  293. }
  294. bool
  295. PostfixIntegrate::IsIntegrated() {
  296. if (Verbose()) {
  297. std::cout << "Checking for any SNFMilter integration in the postfix file " << PostfixMainCfPath << "...";
  298. }
  299. if (!FileExists(PostfixMainCfPath)) {
  300. if (Verbose()) {
  301. std::cout << "file doesn't exist; postfix is not integrated...";
  302. }
  303. OutputVerboseEnd();
  304. return false;
  305. }
  306. bool Integrated = false;
  307. std::ifstream Input;
  308. Input.open(PostfixMainCfPath.c_str()); // Read the contents.
  309. if (!Input) {
  310. std::string Temp;
  311. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  312. Temp += " for reading: ";
  313. Temp += strerror(errno);
  314. throw std::runtime_error(Temp);
  315. }
  316. PostfixMilterConf MilterConf(PostfixSocketSpec); // Object to update the config line.
  317. std::string Line;
  318. while (getline(Input, Line)) {
  319. MilterConf.ConfLine(Line);
  320. if (MilterConf.IsIntegrated()) { // Check for integration line.
  321. Integrated = true; // Found it.
  322. break;
  323. }
  324. }
  325. Input.close();
  326. if (Input.bad()) {
  327. std::string Temp;
  328. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  329. Temp += " after reading: ";
  330. Temp += strerror(errno);
  331. throw std::runtime_error(Temp);
  332. }
  333. if (Verbose()) {
  334. if (Integrated) {
  335. std::cout << "found '" << Line << "'...";
  336. } else {
  337. std::cout << "none found...";
  338. }
  339. }
  340. OutputVerboseEnd();
  341. return Integrated;
  342. }
  343. bool
  344. PostfixIntegrate::DefaultIsChrooted() {
  345. return PostfixDefaultIsChrooted;
  346. }
  347. bool
  348. PostfixIntegrate::MtaConfigurationIsChrooted() {
  349. std::string File;
  350. std::ifstream Input;
  351. File = PostfixMasterCfPath;
  352. Input.open(File.c_str());
  353. if (!Input) {
  354. std::string Temp;
  355. Temp = "Error opening postfix configuration file " + File;
  356. Temp += " for reading: ";
  357. Temp += strerror(errno);
  358. throw std::runtime_error(Temp);
  359. }
  360. std::string Line;
  361. bool ConfigurationIsChrooted = false;
  362. while (getline(Input, Line)) {
  363. if (CheckForString(Line, "smtp")) { // Check for smtp line.
  364. std::istringstream Buffer(Line); // Parse buffer line.
  365. std::string Token[8];
  366. for (unsigned int iToken = 0; iToken < 8; iToken++) {
  367. Buffer >> Token[iToken];
  368. }
  369. if ( ("y" == Token[4]) || ("-" == Token[4]) ) {
  370. Input.close();
  371. if (Input.bad()) {
  372. std::string Temp;
  373. Temp = "Error closing the postfix configuration file " + File;
  374. Temp += " after reading: ";
  375. Temp += strerror(errno);
  376. throw std::runtime_error(Temp);
  377. }
  378. return true;
  379. }
  380. }
  381. }
  382. Input.close();
  383. if (Input.bad()) {
  384. std::string Temp;
  385. Temp = "Error closing the rulebase download script file " + File;
  386. Temp += " after reading: ";
  387. Temp += strerror(errno);
  388. throw std::runtime_error(Temp);
  389. }
  390. return false;
  391. }