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

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