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.

MainClass.cpp 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. //
  2. // Created by robin on 8/8/15.
  3. //
  4. #include <iostream>
  5. #include <fstream>
  6. #include <sysexits.h>
  7. #include <jsoncpp/json/json.h>
  8. #include <cstring>
  9. #include "CommandLineParser.h"
  10. #include "MainClass.h"
  11. MainClass* MainClass::_instance = nullptr;
  12. MainClass *MainClass::getInstance()
  13. {
  14. return _instance;
  15. }
  16. sfsistat mlfi_header(SMFICTX *ctx)
  17. {
  18. return MainClass::getInstance()->mlfiHeader(ctx);
  19. }
  20. MainClass::MainClass(int argc, char *argv[])
  21. : _argc(argc)
  22. , _argv(argv)
  23. {
  24. _instance = this;
  25. _cryptoBusiness = std::make_shared<CryptoBusiness>();
  26. }
  27. MainClass::~MainClass()
  28. {
  29. }
  30. int MainClass::main()
  31. {
  32. CommandLineParser commandLineParser(_argc, _argv);
  33. CommandLineOption configOption("config", 'c', "Use FILE as configuration file.", "FILE", "/etc/milter-sasl/milter-sasl.json");
  34. commandLineParser.addOption(&configOption);
  35. CommandLineOption decryptOption("decrypt", 'd', "Decrypt DATA and exit. Can be specified multiple times. Use - to read from stdin.", "DATA");
  36. commandLineParser.addOption(&decryptOption);
  37. CommandLineOption socketOption("milter", 'm', "Launch milter and specify the socket to listen on (eg: inet:4242@localhost).", "SOCKET");
  38. commandLineParser.addOption(&socketOption);
  39. CommandLineOption helpOption("help", 'h', "Show this help.");
  40. commandLineParser.addOption(&helpOption);
  41. if (!commandLineParser.parse())
  42. {
  43. return commandLineParser.showHelp(EX_USAGE, true);
  44. }
  45. if (helpOption.isSet())
  46. {
  47. return commandLineParser.showHelp(0, false);
  48. }
  49. auto configFile = configOption.getValue();
  50. auto configResult = loadConfig(configFile);
  51. if (configResult != 0)
  52. {
  53. std::cerr << "Failed to read configuration file: " << strerror(configResult) << std::endl;
  54. return EX_NOINPUT;
  55. }
  56. else if (socketOption.isSet())
  57. {
  58. return launchMilter(socketOption.getValue());
  59. }
  60. else if (decryptOption.isSet())
  61. {
  62. return launchDecrypt(decryptOption.getValues());
  63. }
  64. return commandLineParser.showHelp(EX_USAGE, true);
  65. }
  66. sfsistat MainClass::mlfiHeader(SMFICTX *ctx)
  67. {
  68. Json::Value root;
  69. auto auth_authen = smfi_getsymval(ctx, (char*)"{auth_authen}");
  70. if (auth_authen)
  71. {
  72. root["auth_authen"] = randomizeString(auth_authen);
  73. }
  74. auto auth_author = smfi_getsymval(ctx, (char*)"{auth_author}");
  75. if (auth_author)
  76. {
  77. root["auth_author"] = randomizeString(auth_author);
  78. }
  79. auto auth_type = smfi_getsymval(ctx, (char*)"{auth_type}");
  80. if (auth_type)
  81. {
  82. root["auth_type"] = randomizeString(auth_type);
  83. }
  84. Json::StyledWriter w;
  85. auto json = w.write(root);
  86. auto encrypted = _cryptoBusiness->encryptToHex(json);
  87. smfi_addheader(ctx, (char*)"X-Sasl-User", (char*)encrypted.c_str());
  88. return SMFIS_CONTINUE;
  89. }
  90. int MainClass::loadConfig(const std::string& filePath)
  91. {
  92. std::ifstream stream(filePath, std::ifstream::in);
  93. if (stream)
  94. {
  95. Json::Reader reader;
  96. Json::Value root;
  97. reader.parse(stream, root);
  98. _cryptoBusiness->setKey(root["key"].asString());
  99. }
  100. return errno;
  101. }
  102. int MainClass::launchMilter(const std::string &socket)
  103. {
  104. srand(time(nullptr));
  105. struct smfiDesc smfilter =
  106. {
  107. (char*)"milter-sasl", /* filter name */
  108. SMFI_VERSION, /* version code -- do not change */
  109. SMFIF_ADDHDRS, /* flags */
  110. NULL, /* connection info filter */
  111. NULL, /* SMTP HELO command filter */
  112. NULL, /* envelope sender filter */
  113. NULL, /* envelope recipient filter */
  114. NULL, /* header filter */
  115. NULL, /* end of header */
  116. NULL, /* body block filter */
  117. mlfi_header, /* end of message */
  118. NULL, /* message aborted */
  119. NULL, /* connection cleanup */
  120. NULL, /* unknown/unimplemented SMTP commands */
  121. NULL, /* DATA command filter */
  122. NULL /* option negotiation at connection startup */
  123. };
  124. if (smfi_setconn((char*)socket.c_str()) == MI_FAILURE)
  125. {
  126. std::cerr << "smfi_setconn failed" << std::endl;
  127. return EX_UNAVAILABLE;
  128. }
  129. if (smfi_register(smfilter) == MI_FAILURE)
  130. {
  131. std::cerr << "smfi_register failed" << std::endl;
  132. return EX_UNAVAILABLE;
  133. }
  134. return smfi_main();
  135. }
  136. int MainClass::launchDecrypt(const std::vector<std::string> values)
  137. {
  138. for (auto value : values)
  139. {
  140. if (value == "-")
  141. {
  142. std::cin >> value;
  143. }
  144. std::cout << _cryptoBusiness->decryptFromHex(value) << std::endl;
  145. }
  146. return 0;
  147. }
  148. std::string MainClass::randomizeString(const std::string &str)
  149. {
  150. int cc = 2;
  151. std::string out;
  152. for (int i = 0; i < cc; ++i)
  153. {
  154. auto c = 'a' + (rand() % 26);
  155. out.push_back((char)c);
  156. }
  157. out += "|" + str + "|";
  158. for (int i = 0; i < cc; ++i)
  159. {
  160. auto c = 'a' + (rand() % 26);
  161. out.push_back((char)c);
  162. }
  163. return out;
  164. }