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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  21. // Configuration. ////////////////////////////////////////////////////////////////////////////////////////
  22. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  23. const std::string SnfMilterMainCfSearchString("Added by PostfixIntegrate");
  24. const std::string SnfMilterMainCfIntegrationString("smtpd_milters = unix:/var/snf-milter/socket $smtpd_milters # Added by PostfixIntegrate");
  25. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  26. // End of configuration. /////////////////////////////////////////////////////////////////////////////////
  27. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  28. void
  29. PostfixIntegrate::SetOperatingSystem(std::string OperatingSystemType) {
  30. MtaIsRunningCommand = "ps axl | grep -v grep | grep -q 'postfix/master'";
  31. if ("OpenBSD" == OperatingSystemType) {
  32. PostfixMainCfPath = "/usr/local/etc/postfix/main.cf";
  33. PostfixMasterCfPath = "/usr/local/etc/postfix/master.cf";
  34. ReloadMtaCommand = "/usr/local/sbin/postfix reload";
  35. } else if ("FreeBSD" == OperatingSystemType) {
  36. PostfixMainCfPath = "/etc/postfix/main.cf";
  37. PostfixMasterCfPath = "/etc/postfix/master.cf";
  38. ReloadMtaCommand = "/usr/local/sbin/postfix reload";
  39. } else if ("Ubuntu" == OperatingSystemType) {
  40. PostfixMainCfPath = "/etc/postfix/main.cf";
  41. PostfixMasterCfPath = "/etc/postfix/master.cf";
  42. ReloadMtaCommand = "/usr/sbin/postfix reload";
  43. } else if ("RedHat" == OperatingSystemType) {
  44. PostfixMainCfPath = "/etc/postfix/main.cf";
  45. PostfixMasterCfPath = "/etc/postfix/master.cf";
  46. ReloadMtaCommand = "/usr/sbin/postfix reload";
  47. } else if ("Suse" == OperatingSystemType) {
  48. PostfixMainCfPath = "/etc/postfix/main.cf";
  49. PostfixMasterCfPath = "/etc/postfix/master.cf";
  50. ReloadMtaCommand = "/usr/sbin/postfix reload";
  51. } else {
  52. std::ostringstream Temp;
  53. Temp << "***Error from PostfixIntegrate::SetOperatingSystem: Invalid value of OperatingSystemType: "
  54. << OperatingSystemType;
  55. throw std::runtime_error(Temp.str());
  56. }
  57. }
  58. void
  59. PostfixIntegrate::Integrate(FileBackup *SaveFile) {
  60. if (IsIntegrated()) {
  61. return;
  62. }
  63. if (Verbose()) {
  64. std::cout << "Add to postfix file " << PostfixMainCfPath << ": '"
  65. << SnfMilterMainCfIntegrationString << "'...";
  66. }
  67. if (!Explain()) {
  68. SaveFile->CreateBackupFile(PostfixMainCfPath); // Save any existing file.
  69. std::ofstream Output; // Append the configuration.
  70. Output.open(PostfixMainCfPath.c_str(), std::ios::app);
  71. if (!Output) {
  72. std::string Temp;
  73. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  74. Temp += " for writing: ";
  75. Temp += strerror(errno);
  76. throw std::runtime_error(Temp);
  77. }
  78. Output << SnfMilterMainCfIntegrationString << "\n";
  79. if (!Output) {
  80. std::string Temp;
  81. Temp = "Error appending to the postfix configuration file " + PostfixMainCfPath;
  82. Temp += ": ";
  83. Temp += strerror(errno);
  84. throw std::runtime_error(Temp);
  85. }
  86. Output.close();
  87. if (!Output) {
  88. std::string Temp;
  89. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  90. Temp += " after appending: ";
  91. Temp += strerror(errno);
  92. throw std::runtime_error(Temp);
  93. }
  94. }
  95. OutputVerboseEnd();
  96. if (!ReloadMta()) {
  97. std::cerr << "Unable to reload the postfix configuration. Please run "
  98. << "'postfix reload' for the integration with SNFMilter to take effect.";
  99. }
  100. }
  101. void
  102. PostfixIntegrate::Unintegrate(FileBackup *SaveFile) {
  103. if (!IsIntegrated()) {
  104. return;
  105. }
  106. std::ifstream Input;
  107. if (Verbose()) {
  108. std::cout << "Remove integration in postfix file " << PostfixMainCfPath << "--\n";
  109. }
  110. if (!Explain()) {
  111. SaveFile->CreateBackupFile(PostfixMainCfPath); // Save any existing file.
  112. Input.open(PostfixMainCfPath.c_str()); // Read the contents.
  113. if (!Input) {
  114. std::string Temp;
  115. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  116. Temp += " for reading: ";
  117. Temp += strerror(errno);
  118. throw std::runtime_error(Temp);
  119. }
  120. std::string Content;
  121. std::string Line;
  122. while (getline(Input, Line)) {
  123. if (std::string::npos != Line.find(SnfMilterMainCfSearchString)) { // Check for integration line.
  124. if (Verbose()) {
  125. std::cout << " Remove '" << Line << "'...\n";
  126. }
  127. continue; // Do not copy this line.
  128. }
  129. Content += Line + "\n"; // Copy this line.
  130. }
  131. if (!Input.eof()) { // Should be at end-of-file.
  132. std::string Temp;
  133. Temp = "Error reading the postfix configuration file " + PostfixMainCfPath;
  134. Temp += ": ";
  135. Temp += strerror(errno);
  136. throw std::runtime_error(Temp);
  137. }
  138. Input.close();
  139. if (Input.bad()) {
  140. std::string Temp;
  141. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  142. Temp += " after reading: ";
  143. Temp += strerror(errno);
  144. throw std::runtime_error(Temp);
  145. }
  146. if (!Explain()) {
  147. std::ofstream Output; // Write the updated contents.
  148. Output.open(PostfixMainCfPath.c_str(), std::ios::trunc);
  149. if (!Output) {
  150. std::string Temp;
  151. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  152. Temp += " for writing: ";
  153. Temp += strerror(errno);
  154. throw std::runtime_error(Temp);
  155. }
  156. Output << Content;
  157. if (!Output) {
  158. std::string Temp;
  159. Temp = "Error writing the postfix configuration file " + PostfixMainCfPath;
  160. Temp += ": ";
  161. Temp += strerror(errno);
  162. throw std::runtime_error(Temp);
  163. }
  164. Output.close();
  165. if (!Output) {
  166. std::string Temp;
  167. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  168. Temp += " after writing: ";
  169. Temp += strerror(errno);
  170. throw std::runtime_error(Temp);
  171. }
  172. }
  173. }
  174. OutputVerboseEnd();
  175. if (!ReloadMta()) {
  176. std::cerr << "Unable to reload the postfix configuration. Please run "
  177. << "'postfix reload' for the integration with SNFMilter to take effect.";
  178. }
  179. }
  180. bool
  181. PostfixIntegrate::MtaIsRunningDetected() {
  182. if (Verbose()) {
  183. std::cout << "Checking whether postfix is detected to be running...";
  184. }
  185. bool IsRunningDetected;
  186. IsRunningDetected = (std::system(MtaIsRunningCommand.c_str()) == 0);
  187. if (Verbose()) {
  188. std::cout << (IsRunningDetected ? "yes..." : "no...");
  189. }
  190. OutputVerboseEnd();
  191. return IsRunningDetected;
  192. }
  193. bool
  194. PostfixIntegrate::ReloadMta() {
  195. if (!MtaIsRunningDetected()) {
  196. return true;
  197. }
  198. if (Verbose()) {
  199. std::cout << "Reloading postfix...\n";
  200. std::cout.flush();
  201. }
  202. bool Succeeded;
  203. if (!Explain()) {
  204. Succeeded = (std::system(ReloadMtaCommand.c_str()) == 0);
  205. if (Verbose()) {
  206. std::cout << (Succeeded ? "succeeded..." : "failed...");
  207. }
  208. }
  209. OutputVerboseEnd();
  210. return Succeeded;
  211. }
  212. bool
  213. PostfixIntegrate::IsIntegrated() {
  214. if (Verbose()) {
  215. std::cout << "Checking for any SNFMilter integration in the postfix file " << PostfixMainCfPath << "...";
  216. }
  217. if (!FileExists(PostfixMainCfPath)) {
  218. if (Verbose()) {
  219. std::cout << "file doesn't exist; postfix is not integrated...";
  220. }
  221. OutputVerboseEnd();
  222. return false;
  223. }
  224. bool Integrated = false;
  225. std::ifstream Input;
  226. Input.open(PostfixMainCfPath.c_str()); // Read the contents.
  227. if (!Input) {
  228. std::string Temp;
  229. Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
  230. Temp += " for reading: ";
  231. Temp += strerror(errno);
  232. throw std::runtime_error(Temp);
  233. }
  234. std::string Line;
  235. while (getline(Input, Line)) {
  236. if (std::string::npos != Line.find(SnfMilterMainCfSearchString)) { // Check for integration line.
  237. Integrated = true; // Found it.
  238. break;
  239. }
  240. }
  241. Input.close();
  242. if (Input.bad()) {
  243. std::string Temp;
  244. Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
  245. Temp += " after reading: ";
  246. Temp += strerror(errno);
  247. throw std::runtime_error(Temp);
  248. }
  249. if (Verbose()) {
  250. if (Integrated) {
  251. std::cout << "found '" << Line << "'...";
  252. } else {
  253. std::cout << "none found...";
  254. }
  255. }
  256. OutputVerboseEnd();
  257. return Integrated;
  258. }