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 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  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. std::ifstream Input;
  73. if (Verbose()) {
  74. std::cout << "Integrate with postfix...\n";
  75. }
  76. if (!Explain()) {
  77. SaveFile->CreateBackupFile(PostfixMainCfPath); // Save any existing file.
  78. Input.open(PostfixMainCfPath.c_str()); // Read the contents.
  79. if (!Input) {
  80. std::string Temp;
  81. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  82. Temp += " for reading: ";
  83. Temp += strerror(errno);
  84. throw std::runtime_error(Temp);
  85. }
  86. std::string Content;
  87. std::string Line;
  88. bool ModifiedLine = false;
  89. PostfixMilterConf MilterConf(PostfixSocketSpec); // Object to update the config line.
  90. while (getline(Input, Line)) {
  91. MilterConf.ConfLine(Line); // Load the object with the line.
  92. if (MilterConf.IsMilterLine() && !ModifiedLine) { // Check for milter integration line.
  93. // Ignore subsequence integration lines.
  94. MilterConf.AddIntegration(); // Found milter line. Add integration.
  95. if (Verbose()) {
  96. std::cout << " Replace '" << Line << "' with '"
  97. << MilterConf.ConfLine() << "'...\n";
  98. }
  99. Line = MilterConf.ConfLine(); // Copy updated line.
  100. ModifiedLine = true;
  101. }
  102. Content += Line + "\n"; // Copy this line.
  103. }
  104. if (!ModifiedLine) {
  105. MilterConf.ConfLine("");
  106. MilterConf.AddIntegration();
  107. if (Verbose()) {
  108. std::cout << " Add '" << MilterConf.ConfLine() << "'...\n";
  109. }
  110. Content += MilterConf.ConfLine() + "\n";
  111. }
  112. if (!Input.eof()) { // Should be at end-of-file.
  113. std::string Temp;
  114. Temp = "Error reading the postfix configuration file " + PostfixMainCfPath;
  115. Temp += ": ";
  116. Temp += strerror(errno);
  117. throw std::runtime_error(Temp);
  118. }
  119. Input.close();
  120. if (Input.bad()) {
  121. std::string Temp;
  122. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  123. Temp += " after reading: ";
  124. Temp += strerror(errno);
  125. throw std::runtime_error(Temp);
  126. }
  127. if (!Explain()) {
  128. std::ofstream Output; // Write the updated contents.
  129. Output.open(PostfixMainCfPath.c_str(), std::ios::trunc);
  130. if (!Output) {
  131. std::string Temp;
  132. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  133. Temp += " for writing: ";
  134. Temp += strerror(errno);
  135. throw std::runtime_error(Temp);
  136. }
  137. Output << Content;
  138. if (!Output) {
  139. std::string Temp;
  140. Temp = "Error writing the postfix configuration file " + PostfixMainCfPath;
  141. Temp += ": ";
  142. Temp += strerror(errno);
  143. throw std::runtime_error(Temp);
  144. }
  145. Output.close();
  146. if (!Output) {
  147. std::string Temp;
  148. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  149. Temp += " after writing: ";
  150. Temp += strerror(errno);
  151. throw std::runtime_error(Temp);
  152. }
  153. }
  154. }
  155. OutputVerboseEnd();
  156. if (!ReloadMta()) {
  157. std::cerr << "Unable to reload the postfix configuration. Please run "
  158. << "'postfix reload' for the integration with SNFMilter to take effect.";
  159. }
  160. }
  161. void
  162. PostfixIntegrate::Unintegrate(FileBackup *SaveFile) {
  163. if (!IsIntegrated()) {
  164. return;
  165. }
  166. std::ifstream Input;
  167. if (Verbose()) {
  168. std::cout << "Remove integration in postfix file " << PostfixMainCfPath << "--\n";
  169. }
  170. if (!Explain()) {
  171. SaveFile->CreateBackupFile(PostfixMainCfPath); // Save any existing file.
  172. Input.open(PostfixMainCfPath.c_str()); // Read the contents.
  173. if (!Input) {
  174. std::string Temp;
  175. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  176. Temp += " for reading: ";
  177. Temp += strerror(errno);
  178. throw std::runtime_error(Temp);
  179. }
  180. std::string Content;
  181. std::string Line;
  182. PostfixMilterConf MilterConf(PostfixSocketSpec); // Object to update the config line.
  183. while (getline(Input, Line)) {
  184. MilterConf.ConfLine(Line); // Load the object with the line.
  185. if (MilterConf.IsIntegrated()) { // Check for integration.
  186. MilterConf.RemoveIntegration(); // Integrated. Remove the milter spec.
  187. if (Verbose()) {
  188. std::cout << " Replace '" << Line << "' with '"
  189. << MilterConf.ConfLine() << "'...\n";
  190. }
  191. Content += MilterConf.ConfLine(); // Copy updated line.
  192. if (MilterConf.ConfLine() != "") {
  193. Content += "\n";
  194. }
  195. continue;
  196. }
  197. Content += Line + "\n"; // Copy this line.
  198. }
  199. if (!Input.eof()) { // Should be at end-of-file.
  200. std::string Temp;
  201. Temp = "Error reading the postfix configuration file " + PostfixMainCfPath;
  202. Temp += ": ";
  203. Temp += strerror(errno);
  204. throw std::runtime_error(Temp);
  205. }
  206. Input.close();
  207. if (Input.bad()) {
  208. std::string Temp;
  209. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  210. Temp += " after reading: ";
  211. Temp += strerror(errno);
  212. throw std::runtime_error(Temp);
  213. }
  214. if (!Explain()) {
  215. std::ofstream Output; // Write the updated contents.
  216. Output.open(PostfixMainCfPath.c_str(), std::ios::trunc);
  217. if (!Output) {
  218. std::string Temp;
  219. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  220. Temp += " for writing: ";
  221. Temp += strerror(errno);
  222. throw std::runtime_error(Temp);
  223. }
  224. Output << Content;
  225. if (!Output) {
  226. std::string Temp;
  227. Temp = "Error writing the postfix configuration file " + PostfixMainCfPath;
  228. Temp += ": ";
  229. Temp += strerror(errno);
  230. throw std::runtime_error(Temp);
  231. }
  232. Output.close();
  233. if (!Output) {
  234. std::string Temp;
  235. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  236. Temp += " after writing: ";
  237. Temp += strerror(errno);
  238. throw std::runtime_error(Temp);
  239. }
  240. }
  241. }
  242. OutputVerboseEnd();
  243. if (!ReloadMta()) {
  244. std::cerr << "Unable to reload the postfix configuration. Please run "
  245. << "'postfix reload' for the integration with SNFMilter to take effect.";
  246. }
  247. }
  248. bool
  249. PostfixIntegrate::MtaIsRunningDetected() {
  250. if (Verbose()) {
  251. std::cout << "Checking whether postfix is detected to be running...";
  252. }
  253. bool IsRunningDetected;
  254. IsRunningDetected = (std::system(MtaIsRunningCommand.c_str()) == 0);
  255. if (Verbose()) {
  256. std::cout << (IsRunningDetected ? "yes..." : "no...");
  257. }
  258. OutputVerboseEnd();
  259. return IsRunningDetected;
  260. }
  261. bool
  262. PostfixIntegrate::ReloadMta() {
  263. if (!MtaIsRunningDetected()) {
  264. return true;
  265. }
  266. if (Verbose()) {
  267. std::cout << "Reloading postfix...\n";
  268. std::cout.flush();
  269. }
  270. bool Succeeded;
  271. if (!Explain()) {
  272. Succeeded = (std::system(ReloadMtaCommand.c_str()) == 0);
  273. if (Verbose()) {
  274. std::cout << (Succeeded ? "succeeded..." : "failed...");
  275. }
  276. }
  277. OutputVerboseEnd();
  278. return Succeeded;
  279. }
  280. bool
  281. PostfixIntegrate::IsIntegrated() {
  282. if (Verbose()) {
  283. std::cout << "Checking for any SNFMilter integration in the postfix file " << PostfixMainCfPath << "...";
  284. }
  285. if (!FileExists(PostfixMainCfPath)) {
  286. if (Verbose()) {
  287. std::cout << "file doesn't exist; postfix is not integrated...";
  288. }
  289. OutputVerboseEnd();
  290. return false;
  291. }
  292. bool Integrated = false;
  293. std::ifstream Input;
  294. Input.open(PostfixMainCfPath.c_str()); // Read the contents.
  295. if (!Input) {
  296. std::string Temp;
  297. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  298. Temp += " for reading: ";
  299. Temp += strerror(errno);
  300. throw std::runtime_error(Temp);
  301. }
  302. PostfixMilterConf MilterConf(PostfixSocketSpec); // Object to update the config line.
  303. std::string Line;
  304. while (getline(Input, Line)) {
  305. MilterConf.ConfLine(Line);
  306. if (MilterConf.IsIntegrated()) { // Check for integration line.
  307. Integrated = true; // Found it.
  308. break;
  309. }
  310. }
  311. Input.close();
  312. if (Input.bad()) {
  313. std::string Temp;
  314. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  315. Temp += " after reading: ";
  316. Temp += strerror(errno);
  317. throw std::runtime_error(Temp);
  318. }
  319. if (Verbose()) {
  320. if (Integrated) {
  321. std::cout << "found '" << Line << "'...";
  322. } else {
  323. std::cout << "none found...";
  324. }
  325. }
  326. OutputVerboseEnd();
  327. return Integrated;
  328. }