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.

SendmailIntegrate.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. // /file SendmailIntegrate.cpp
  2. //
  3. // Copyright (C) 2012, ARM Research Labs, LLC.
  4. // See www.armresearch.com for the copyright terms.
  5. //
  6. // This file contains the functions for SendmailIntegrate.
  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 "SendmailIntegrate.hpp"
  20. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  21. // Configuration. ////////////////////////////////////////////////////////////////////////////////////////
  22. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  23. const std::string MtaIsRunningCommand("ps axl | grep -v grep | grep -q ' sendmail: '");
  24. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  25. // End of configuration. /////////////////////////////////////////////////////////////////////////////////
  26. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  27. void
  28. SendmailIntegrate::SetOperatingSystem(std::string OperatingSystemType) {
  29. ProcmailRcFileName = "/etc/procmailrc";
  30. if ("OpenBSD" == OperatingSystemType) {
  31. IntegrationIsSupported = false;
  32. } else if ("FreeBSD" == OperatingSystemType) {
  33. IntegrationIsSupported = false;
  34. } else if ("Ubuntu" == OperatingSystemType) {
  35. IntegrationIsSupported = true;
  36. SendmailSendmailMcPath = "/etc/mail/sendmail.mc";
  37. SendmailSendmailCfPath = "/etc/mail/sendmail.cf";
  38. SnfSnifferDirName = "/var/spool/postfix/snf-server";
  39. SnfSnifferFileName = SnfSnifferDirName + "/snfSnifferFilter";
  40. SnfSnifferSampleFileName = "/usr/sbin/snfSnifferFilter.sample";
  41. BuildInstallSendmailCfFile = "(cd /etc/mail && make)";
  42. ReloadMtaCommand = "/etc/init.d/sendmail reload";
  43. FileToBackup.push_back(SendmailSendmailMcPath);
  44. FileToBackup.push_back(SendmailSendmailCfPath);
  45. } else if ("RedHat" == OperatingSystemType) {
  46. IntegrationIsSupported = true;
  47. SendmailSendmailMcPath = "/etc/mail/sendmail.mc";
  48. SendmailSendmailCfPath = "/etc/mail/sendmail.cf";
  49. SnfSnifferDirName = "/usr/sbin";
  50. SnfSnifferFileName = SnfSnifferDirName + "/snfSnifferFilter";
  51. SnfSnifferSampleFileName = SnfSnifferDirName + "/snfSnifferFilter.sample";
  52. BuildInstallSendmailCfFile = "(cd /etc/mail && make)";
  53. ReloadMtaCommand = "/etc/init.d/sendmail reload";
  54. FileToBackup.push_back(SendmailSendmailMcPath);
  55. FileToBackup.push_back(SendmailSendmailCfPath);
  56. } else if ("Suse" == OperatingSystemType) {
  57. IntegrationIsSupported = true;
  58. SendmailSendmailMcPath = "/etc/mail/linux.mc";
  59. SendmailSendmailCfPath = "/etc/mail/sendmail.cf";
  60. SnfSnifferDirName = "/usr/sbin";
  61. SnfSnifferFileName = SnfSnifferDirName + "/snfSnifferFilter";
  62. SnfSnifferSampleFileName = SnfSnifferDirName + "/snfSnifferFilter.sample";
  63. BuildInstallSendmailCfFile = "(cd /etc/mail && rm -f sendmail.cf && m4 /etc/mail/linux.mc > sendmail.cf)";
  64. ReloadMtaCommand = "/etc/init.d/sendmail reload";
  65. FileToBackup.push_back(SendmailSendmailMcPath);
  66. FileToBackup.push_back(SendmailSendmailCfPath);
  67. } else {
  68. std::ostringstream Temp;
  69. Temp << "***Error from SendmailIntegrate::SetOperatingSystem: Invalid value of OperatingSystemType: "
  70. << OperatingSystemType;
  71. throw std::runtime_error(Temp.str());
  72. }
  73. ProcmailRcSnifferIntegration = ":0 fw\n| " + SnfSnifferFileName;
  74. ProcmailRcSnifferIntegration += "\n";
  75. }
  76. void
  77. SendmailIntegrate::Integrate(FileBackup *SaveFile) {
  78. if (!IntegrationIsSupported) {
  79. return;
  80. }
  81. if (IsIntegrated()) {
  82. return;
  83. }
  84. if (Verbose()) {
  85. std::cout << "Create " << SnfSnifferFileName << " if it doesn't exist...";
  86. }
  87. if (!Explain()) {
  88. if (!FileExists(SnfSnifferFileName)) { // Create SnfSnifferFilter script
  89. // if it doesn't exist.
  90. SaveFile->CreateBackupFile(SnfSnifferFileName);
  91. if (!FileExists(SnfSnifferDirName)) {
  92. MkDir(SnfSnifferDirName);
  93. }
  94. SetMode(SnfSnifferDirName, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
  95. SetOwnerGroup(SnfSnifferDirName);
  96. Copy(SnfSnifferSampleFileName, SnfSnifferFileName);
  97. SetMode(SnfSnifferFileName, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
  98. SetOwnerGroup(SnfSnifferFileName);
  99. }
  100. }
  101. OutputVerboseEnd();
  102. if (Verbose()) {
  103. std::cout << "Add\n\n" << ProcmailRcSnifferIntegration << "\n\nto " << ProcmailRcFileName << "...";
  104. }
  105. std::string ProcmailRcFileContent;
  106. if (!Explain()) {
  107. if (FileExists(ProcmailRcFileName)) { // Read any existing procmail configuration.
  108. std::ifstream Input;
  109. Input.open(ProcmailRcFileName.c_str());
  110. if (!Input) {
  111. std::string Temp;
  112. Temp = "Error opening the procmail configuration file " + ProcmailRcFileName;
  113. Temp += " for reading: ";
  114. Temp += strerror(errno);
  115. throw std::runtime_error(Temp);
  116. }
  117. if (!Input.eof()) {
  118. std::ostringstream Buffer;
  119. Buffer << Input.rdbuf();
  120. ProcmailRcFileContent = Buffer.str();
  121. }
  122. Input.close();
  123. if (!Input) {
  124. std::string Temp;
  125. Temp = "Error closing the procmail configuration file " + ProcmailRcFileName;
  126. Temp += " after reading: ";
  127. Temp += strerror(errno);
  128. throw std::runtime_error(Temp);
  129. }
  130. }
  131. ProcmailRcFileContent = ProcmailRcSnifferIntegration + ProcmailRcFileContent;
  132. SaveFile->CreateBackupFile(ProcmailRcFileName);
  133. std::ofstream Output; // Write the updated contents.
  134. Output.open(ProcmailRcFileName.c_str(), std::ios::trunc);
  135. if (!Output) {
  136. std::string Temp;
  137. Temp = "Error opening the procmail configuration file " + ProcmailRcFileName;
  138. Temp += " for writing: ";
  139. Temp += strerror(errno);
  140. throw std::runtime_error(Temp);
  141. }
  142. Output << ProcmailRcFileContent;
  143. if (!Output) {
  144. std::string Temp;
  145. Temp = "Error writing the procmail configuration file " + ProcmailRcFileName;
  146. Temp += ": ";
  147. Temp += strerror(errno);
  148. throw std::runtime_error(Temp);
  149. }
  150. Output.close();
  151. if (!Output) {
  152. std::string Temp;
  153. Temp = "Error closing the procmail configuration file " + ProcmailRcFileName;
  154. Temp += " after writing: ";
  155. Temp += strerror(errno);
  156. throw std::runtime_error(Temp);
  157. }
  158. }
  159. OutputVerboseEnd();
  160. if (!ReloadMta()) {
  161. std::cerr << "Unable to reload the sendmail configuration. Please reload "
  162. << " the sendmail configuration for the integration with SNFServer to take effect.";
  163. }
  164. }
  165. void
  166. SendmailIntegrate::Unintegrate(FileBackup *SaveFile) {
  167. if (!IntegrationIsSupported) {
  168. return;
  169. }
  170. if (!IsIntegrated()) {
  171. return;
  172. }
  173. std::ifstream Input;
  174. if (Verbose()) {
  175. std::cout << "Remove integration in procmail file " << ProcmailRcFileName << "--\n";
  176. }
  177. if (!Explain()) {
  178. Input.open(ProcmailRcFileName.c_str());
  179. if (!Input) {
  180. std::string Temp;
  181. Temp = "Error opening the procmail configuration file " + ProcmailRcFileName;
  182. Temp += " for reading: ";
  183. Temp += strerror(errno);
  184. throw std::runtime_error(Temp);
  185. }
  186. std::ostringstream ContentStream;
  187. ContentStream << Input.rdbuf();
  188. Input.close();
  189. if (!Input) {
  190. std::string Temp;
  191. Temp = "Error closing the procmail configuration file " + ProcmailRcFileName;
  192. Temp += ": ";
  193. Temp += strerror(errno);
  194. throw std::runtime_error(Temp);
  195. }
  196. std::string Content;
  197. Content = ContentStream.str();
  198. if (Verbose()) {
  199. std::cout << " Remove all occurances of\n\n" << ProcmailRcSnifferIntegration << "\n\n"
  200. << " from" << ProcmailRcFileName << "...\n";
  201. }
  202. std::string::size_type IntegrationBegin = std::string::npos;
  203. while ((IntegrationBegin = Content.find(ProcmailRcSnifferIntegration)) != std::string::npos) {
  204. Content.erase(IntegrationBegin, ProcmailRcSnifferIntegration.length());
  205. }
  206. SaveFile->CreateBackupFile(ProcmailRcFileName);
  207. std::ofstream Output; // Write the updated contents.
  208. Output.open(ProcmailRcFileName.c_str(), std::ios::trunc);
  209. if (!Output) {
  210. std::string Temp;
  211. Temp = "Error opening the procmail configuration file " + ProcmailRcFileName;
  212. Temp += " for writing: ";
  213. Temp += strerror(errno);
  214. throw std::runtime_error(Temp);
  215. }
  216. Output << Content;
  217. if (!Output) {
  218. std::string Temp;
  219. Temp = "Error writing the procmail configuration file " + ProcmailRcFileName;
  220. Temp += ": ";
  221. Temp += strerror(errno);
  222. throw std::runtime_error(Temp);
  223. }
  224. Output.close();
  225. if (!Output) {
  226. std::string Temp;
  227. Temp = "Error closing the procmail configuration file " + ProcmailRcFileName;
  228. Temp += " after writing: ";
  229. Temp += strerror(errno);
  230. throw std::runtime_error(Temp);
  231. }
  232. }
  233. OutputVerboseEnd();
  234. if (!ReloadMta()) {
  235. std::cerr << "Unable to reload the sendmail configuration. Please run "
  236. << "'sendmail reload' for the integration with SNFServer to take effect.";
  237. }
  238. }
  239. bool
  240. SendmailIntegrate::MtaIsRunningDetected() {
  241. if (Verbose()) {
  242. std::cout << "Checking whether sendmail is detected to be running...";
  243. }
  244. bool IsRunningDetected;
  245. IsRunningDetected = (std::system(MtaIsRunningCommand.c_str()) == 0);
  246. if (Verbose()) {
  247. std::cout << (IsRunningDetected ? "yes..." : "no...");
  248. }
  249. OutputVerboseEnd();
  250. return IsRunningDetected;
  251. }
  252. bool
  253. SendmailIntegrate::ReloadMta() {
  254. if (!MtaIsRunningDetected()) {
  255. return true;
  256. }
  257. if (Verbose()) {
  258. std::cout << "Reloading sendmail with the command '"
  259. << ReloadMtaCommand << "'...\n";
  260. std::cout.flush();
  261. }
  262. bool Succeeded;
  263. if (!Explain()) {
  264. Succeeded = (std::system(ReloadMtaCommand.c_str()) == 0);
  265. if (Verbose()) {
  266. std::cout << (Succeeded ? "succeeded..." : "failed...");
  267. }
  268. }
  269. OutputVerboseEnd();
  270. return Succeeded;
  271. }
  272. bool
  273. SendmailIntegrate::IsIntegrated() {
  274. if (Verbose()) {
  275. std::cout << "Checking for any SNFServer integration in the procmail file " << ProcmailRcFileName << "...";
  276. }
  277. if (!FileExists(ProcmailRcFileName)) {
  278. if (Verbose()) {
  279. std::cout << "file doesn't exist; sendmail is not integrated...";
  280. }
  281. OutputVerboseEnd();
  282. return false;
  283. }
  284. bool Integrated = false;
  285. std::ifstream Input;
  286. Input.open(ProcmailRcFileName.c_str()); // Read the contents.
  287. if (!Input) {
  288. std::string Temp;
  289. Temp = "Error opening the procmail configuration file " + ProcmailRcFileName;
  290. Temp += " for reading: ";
  291. Temp += strerror(errno);
  292. throw std::runtime_error(Temp);
  293. }
  294. std::string ProcmailRcFileContent;
  295. if (!Input.eof()) {
  296. std::ostringstream Buffer;
  297. Buffer << Input.rdbuf();
  298. ProcmailRcFileContent = Buffer.str();
  299. }
  300. Input.close();
  301. if (!Input) {
  302. std::string Temp;
  303. Temp = "Error closing the procmail configuration file " + ProcmailRcFileName;
  304. Temp += " after reading: ";
  305. Temp += strerror(errno);
  306. throw std::runtime_error(Temp);
  307. }
  308. Integrated = (ProcmailRcFileContent.find(ProcmailRcSnifferIntegration) != std::string::npos);
  309. if (Verbose()) {
  310. if (Integrated) {
  311. std::cout << "found\n\n" << ProcmailRcSnifferIntegration << "\n\n...";
  312. } else {
  313. std::cout << "none found...";
  314. }
  315. }
  316. OutputVerboseEnd();
  317. return Integrated;
  318. }