Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

PostfixIntegrate.cpp 15KB

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