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.

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