123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- //
- // Created by robin on 8/8/15.
- //
-
- #include <iostream>
- #include <fstream>
- #include <sysexits.h>
- #include <jsoncpp/json/json.h>
- #include <cstring>
- #include "CommandLineParser.h"
- #include "MainClass.h"
-
- MainClass* MainClass::_instance = nullptr;
-
- MainClass *MainClass::getInstance()
- {
- return _instance;
- }
-
- sfsistat mlfi_header(SMFICTX *ctx)
- {
- return MainClass::getInstance()->mlfiHeader(ctx);
- }
-
- MainClass::MainClass(int argc, char *argv[])
- : _argc(argc)
- , _argv(argv)
- {
- _instance = this;
- _cryptoBusiness = std::make_shared<CryptoBusiness>();
- }
-
- MainClass::~MainClass()
- {
- }
-
- int MainClass::main()
- {
- CommandLineParser commandLineParser(_argc, _argv);
- CommandLineOption configOption("config", 'c', "Use FILE as configuration file.", "FILE", "/etc/milter-sasl/milter-sasl.json");
- commandLineParser.addOption(&configOption);
- CommandLineOption decryptOption("decrypt", 'd', "Decrypt DATA and exit. Can be specified multiple times. Use - to read from stdin.", "DATA");
- commandLineParser.addOption(&decryptOption);
- CommandLineOption socketOption("milter", 'm', "Launch milter and specify the socket to listen on (eg: inet:4242@localhost).", "SOCKET");
- commandLineParser.addOption(&socketOption);
- CommandLineOption helpOption("help", 'h', "Show this help.");
- commandLineParser.addOption(&helpOption);
-
- if (!commandLineParser.parse())
- {
- return commandLineParser.showHelp(EX_USAGE, true);
- }
-
- if (helpOption.isSet())
- {
- return commandLineParser.showHelp(0, false);
- }
-
- auto configFile = configOption.getValue();
- auto configResult = loadConfig(configFile);
- if (configResult != 0)
- {
- std::cerr << "Failed to read configuration file: " << strerror(configResult) << std::endl;
- return EX_NOINPUT;
- }
- else if (socketOption.isSet())
- {
- return launchMilter(socketOption.getValue());
- }
- else if (decryptOption.isSet())
- {
- return launchDecrypt(decryptOption.getValues());
- }
-
- return commandLineParser.showHelp(EX_USAGE, true);
- }
-
- sfsistat MainClass::mlfiHeader(SMFICTX *ctx)
- {
- Json::Value root;
- auto auth_authen = smfi_getsymval(ctx, (char*)"{auth_authen}");
- if (auth_authen)
- {
- root["auth_authen"] = randomizeString(auth_authen);
- }
- auto auth_author = smfi_getsymval(ctx, (char*)"{auth_author}");
- if (auth_author)
- {
- root["auth_author"] = randomizeString(auth_author);
- }
- auto auth_type = smfi_getsymval(ctx, (char*)"{auth_type}");
- if (auth_type)
- {
- root["auth_type"] = randomizeString(auth_type);
- }
-
- Json::StyledWriter w;
- auto json = w.write(root);
- auto encrypted = _cryptoBusiness->encryptToHex(json);
-
- smfi_addheader(ctx, (char*)"X-Sasl-User", (char*)encrypted.c_str());
-
- return SMFIS_CONTINUE;
- }
-
- int MainClass::loadConfig(const std::string& filePath)
- {
- std::ifstream stream(filePath, std::ifstream::in);
- if (stream)
- {
- Json::Reader reader;
- Json::Value root;
- reader.parse(stream, root);
- _cryptoBusiness->setKey(root["key"].asString());
- }
- return errno;
- }
-
- int MainClass::launchMilter(const std::string &socket)
- {
- srand(time(nullptr));
- struct smfiDesc smfilter =
- {
- (char*)"milter-sasl", /* filter name */
- SMFI_VERSION, /* version code -- do not change */
- SMFIF_ADDHDRS, /* flags */
- NULL, /* connection info filter */
- NULL, /* SMTP HELO command filter */
- NULL, /* envelope sender filter */
- NULL, /* envelope recipient filter */
- NULL, /* header filter */
- NULL, /* end of header */
- NULL, /* body block filter */
- mlfi_header, /* end of message */
- NULL, /* message aborted */
- NULL, /* connection cleanup */
- NULL, /* unknown/unimplemented SMTP commands */
- NULL, /* DATA command filter */
- NULL /* option negotiation at connection startup */
- };
-
- if (smfi_setconn((char*)socket.c_str()) == MI_FAILURE)
- {
- std::cerr << "smfi_setconn failed" << std::endl;
- return EX_UNAVAILABLE;
- }
-
- if (smfi_register(smfilter) == MI_FAILURE)
- {
- std::cerr << "smfi_register failed" << std::endl;
- return EX_UNAVAILABLE;
- }
-
- return smfi_main();
- }
-
- int MainClass::launchDecrypt(const std::vector<std::string> values)
- {
- for (auto value : values)
- {
- if (value == "-")
- {
- std::cin >> value;
- }
- std::cout << _cryptoBusiness->decryptFromHex(value) << std::endl;
- }
- return 0;
- }
-
- std::string MainClass::randomizeString(const std::string &str)
- {
- int cc = 2;
- std::string out;
- for (int i = 0; i < cc; ++i)
- {
- auto c = 'a' + (rand() % 26);
- out.push_back((char)c);
- }
- out += "|" + str + "|";
- for (int i = 0; i < cc; ++i)
- {
- auto c = 'a' + (rand() % 26);
- out.push_back((char)c);
- }
- return out;
- }
|