Commit 543d4451d2a619415d0cdd962ddb161a8a84baf9
1 parent
1b9f0978
Auth plugin init works
It can be defined in the config file, along with options.
Showing
13 changed files
with
382 additions
and
44 deletions
CMakeLists.txt
authplugin.cpp
| ... | ... | @@ -7,10 +7,6 @@ |
| 7 | 7 | |
| 8 | 8 | #include "exceptions.h" |
| 9 | 9 | |
| 10 | -// TODO: error handling on all the calls to the plugin. Exceptions? Passing to the caller? | |
| 11 | -// TODO: where to do the conditionals about whether the plugin is loaded, what to do on error, etc? | |
| 12 | -// -> Perhaps merely log the error (and return 'denied'?)? | |
| 13 | - | |
| 14 | 10 | void mosquitto_log_printf(int level, const char *fmt, ...) |
| 15 | 11 | { |
| 16 | 12 | Logger *logger = Logger::getInstance(); |
| ... | ... | @@ -21,12 +17,18 @@ void mosquitto_log_printf(int level, const char *fmt, ...) |
| 21 | 17 | } |
| 22 | 18 | |
| 23 | 19 | |
| 24 | -AuthPlugin::AuthPlugin() // our configuration object as param | |
| 20 | +AuthPlugin::AuthPlugin(ConfigFileParser &confFileParser) : | |
| 21 | + confFileParser(confFileParser) | |
| 25 | 22 | { |
| 26 | 23 | logger = Logger::getInstance(); |
| 27 | 24 | } |
| 28 | 25 | |
| 29 | -void *AuthPlugin::loadSymbol(void *handle, const char *symbol) | |
| 26 | +AuthPlugin::~AuthPlugin() | |
| 27 | +{ | |
| 28 | + cleanup(); | |
| 29 | +} | |
| 30 | + | |
| 31 | +void *AuthPlugin::loadSymbol(void *handle, const char *symbol) const | |
| 30 | 32 | { |
| 31 | 33 | void *r = dlsym(handle, symbol); |
| 32 | 34 | |
| ... | ... | @@ -41,8 +43,14 @@ void *AuthPlugin::loadSymbol(void *handle, const char *symbol) |
| 41 | 43 | |
| 42 | 44 | void AuthPlugin::loadPlugin(const std::string &pathToSoFile) |
| 43 | 45 | { |
| 46 | + if (pathToSoFile.empty()) | |
| 47 | + return; | |
| 48 | + | |
| 44 | 49 | logger->logf(LOG_INFO, "Loading auth plugin %s", pathToSoFile.c_str()); |
| 45 | 50 | |
| 51 | + initialized = false; | |
| 52 | + wanted = true; | |
| 53 | + | |
| 46 | 54 | if (access(pathToSoFile.c_str(), R_OK) != 0) |
| 47 | 55 | { |
| 48 | 56 | std::ostringstream oss; |
| ... | ... | @@ -72,47 +80,105 @@ void AuthPlugin::loadPlugin(const std::string &pathToSoFile) |
| 72 | 80 | acl_check_v2 = (F_auth_plugin_acl_check_v2)loadSymbol(r, "mosquitto_auth_acl_check"); |
| 73 | 81 | unpwd_check_v2 = (F_auth_plugin_unpwd_check_v2)loadSymbol(r, "mosquitto_auth_unpwd_check"); |
| 74 | 82 | psk_key_get_v2 = (F_auth_plugin_psk_key_get_v2)loadSymbol(r, "mosquitto_auth_psk_key_get"); |
| 83 | + | |
| 84 | + initialized = true; | |
| 75 | 85 | } |
| 76 | 86 | |
| 77 | -int AuthPlugin::init() | |
| 87 | +void AuthPlugin::init() | |
| 78 | 88 | { |
| 79 | - struct mosquitto_auth_opt auth_opts[2]; // TODO: get auth opts from central config object | |
| 80 | - std::memset(&auth_opts, 0, sizeof(struct mosquitto_auth_opt) * 2); | |
| 81 | - int result = init_v2(&pluginData, auth_opts, 2); | |
| 82 | - return result; | |
| 89 | + if (!wanted) | |
| 90 | + return; | |
| 91 | + | |
| 92 | + AuthOptCompatWrap &authOpts = confFileParser.getAuthOptsCompat(); | |
| 93 | + int result = init_v2(&pluginData, authOpts.head(), authOpts.size()); | |
| 94 | + if (result != 0) | |
| 95 | + throw FatalError("Error initialising auth plugin."); | |
| 83 | 96 | } |
| 84 | 97 | |
| 85 | -int AuthPlugin::cleanup() | |
| 98 | +void AuthPlugin::cleanup() | |
| 86 | 99 | { |
| 87 | - struct mosquitto_auth_opt auth_opts[2]; // TODO: get auth opts from central config object | |
| 88 | - std::memset(&auth_opts, 0, sizeof(struct mosquitto_auth_opt) * 2); | |
| 89 | - return cleanup_v2(pluginData, auth_opts, 2); | |
| 100 | + if (!cleanup_v2) | |
| 101 | + return; | |
| 102 | + | |
| 103 | + securityCleanup(false); | |
| 104 | + | |
| 105 | + AuthOptCompatWrap &authOpts = confFileParser.getAuthOptsCompat(); | |
| 106 | + int result = cleanup_v2(pluginData, authOpts.head(), authOpts.size()); | |
| 107 | + if (result != 0) | |
| 108 | + logger->logf(LOG_ERR, "Error cleaning up auth plugin"); // Not doing exception, because we're shutting down anyway. | |
| 90 | 109 | } |
| 91 | 110 | |
| 92 | -int AuthPlugin::securityInit(bool reloading) | |
| 111 | +void AuthPlugin::securityInit(bool reloading) | |
| 93 | 112 | { |
| 94 | - struct mosquitto_auth_opt auth_opts[2]; // TODO: get auth opts from central config object | |
| 95 | - std::memset(&auth_opts, 0, sizeof(struct mosquitto_auth_opt) * 2); | |
| 96 | - return security_init_v2(pluginData, auth_opts, 2, reloading); | |
| 113 | + if (!wanted) | |
| 114 | + return; | |
| 115 | + | |
| 116 | + AuthOptCompatWrap &authOpts = confFileParser.getAuthOptsCompat(); | |
| 117 | + int result = security_init_v2(pluginData, authOpts.head(), authOpts.size(), reloading); | |
| 118 | + if (result != 0) | |
| 119 | + { | |
| 120 | + throw AuthPluginException("Plugin function mosquitto_auth_security_init returned an error. If it didn't log anything, we don't know what it was."); | |
| 121 | + } | |
| 122 | + initialized = true; | |
| 97 | 123 | } |
| 98 | 124 | |
| 99 | -int AuthPlugin::securityCleanup(bool reloading) | |
| 125 | +void AuthPlugin::securityCleanup(bool reloading) | |
| 100 | 126 | { |
| 101 | - struct mosquitto_auth_opt auth_opts[2]; // TODO: get auth opts from central config object | |
| 102 | - std::memset(&auth_opts, 0, sizeof(struct mosquitto_auth_opt) * 2); | |
| 103 | - return security_cleanup_v2(pluginData, auth_opts, 2, reloading); | |
| 127 | + if (!wanted) | |
| 128 | + return; | |
| 129 | + | |
| 130 | + initialized = false; | |
| 131 | + AuthOptCompatWrap &authOpts = confFileParser.getAuthOptsCompat(); | |
| 132 | + int result = security_cleanup_v2(pluginData, authOpts.head(), authOpts.size(), reloading); | |
| 133 | + | |
| 134 | + if (result != 0) | |
| 135 | + { | |
| 136 | + throw AuthPluginException("Plugin function mosquitto_auth_security_cleanup returned an error. If it didn't log anything, we don't know what it was."); | |
| 137 | + } | |
| 104 | 138 | } |
| 105 | 139 | |
| 106 | 140 | AuthResult AuthPlugin::aclCheck(const std::string &clientid, const std::string &username, const std::string &topic, AclAccess access) |
| 107 | 141 | { |
| 142 | + if (!wanted) | |
| 143 | + return AuthResult::success; | |
| 144 | + | |
| 145 | + if (!initialized) | |
| 146 | + { | |
| 147 | + logger->logf(LOG_ERR, "ACL check wanted, but initialization failed. Can't perform check."); | |
| 148 | + return AuthResult::error; | |
| 149 | + } | |
| 150 | + | |
| 108 | 151 | int result = acl_check_v2(pluginData, clientid.c_str(), username.c_str(), topic.c_str(), static_cast<int>(access)); |
| 109 | - return static_cast<AuthResult>(result); | |
| 152 | + AuthResult result_ = static_cast<AuthResult>(result); | |
| 153 | + | |
| 154 | + if (result_ == AuthResult::error) | |
| 155 | + { | |
| 156 | + logger->logf(LOG_ERR, "ACL check by plugin returned error for topic '%s'. If it didn't log anything, we don't know what it was.", topic.c_str()); | |
| 157 | + } | |
| 158 | + | |
| 159 | + return result_; | |
| 110 | 160 | } |
| 111 | 161 | |
| 112 | 162 | AuthResult AuthPlugin::unPwdCheck(const std::string &username, const std::string &password) |
| 113 | 163 | { |
| 164 | + if (!wanted) | |
| 165 | + return AuthResult::success; | |
| 166 | + | |
| 167 | + if (!initialized) | |
| 168 | + { | |
| 169 | + logger->logf(LOG_ERR, "Username+password check wanted, but initialization failed. Can't perform check."); | |
| 170 | + return AuthResult::error; | |
| 171 | + } | |
| 172 | + | |
| 114 | 173 | int result = unpwd_check_v2(pluginData, username.c_str(), password.c_str()); |
| 115 | - return static_cast<AuthResult>(result); | |
| 174 | + AuthResult r = static_cast<AuthResult>(result); | |
| 175 | + | |
| 176 | + if (r == AuthResult::error) | |
| 177 | + { | |
| 178 | + logger->logf(LOG_ERR, "Username+password check by plugin returned error for user '%s'. If it didn't log anything, we don't know what it was.", username.c_str()); | |
| 179 | + } | |
| 180 | + | |
| 181 | + return r; | |
| 116 | 182 | } |
| 117 | 183 | |
| 118 | 184 | ... | ... |
authplugin.h
| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | #include <cstring> |
| 6 | 6 | |
| 7 | 7 | #include "logger.h" |
| 8 | +#include "configfileparser.h" | |
| 8 | 9 | |
| 9 | 10 | // Compatible with Mosquitto |
| 10 | 11 | enum class AclAccess |
| ... | ... | @@ -23,11 +24,6 @@ enum class AuthResult |
| 23 | 24 | error = 13 |
| 24 | 25 | }; |
| 25 | 26 | |
| 26 | -struct mosquitto_auth_opt { | |
| 27 | - char *key; | |
| 28 | - char *value; | |
| 29 | -}; | |
| 30 | - | |
| 31 | 27 | typedef int (*F_auth_plugin_version)(void); |
| 32 | 28 | |
| 33 | 29 | typedef int (*F_auth_plugin_init_v2)(void **, struct mosquitto_auth_opt *, int); |
| ... | ... | @@ -55,18 +51,25 @@ class AuthPlugin |
| 55 | 51 | F_auth_plugin_unpwd_check_v2 unpwd_check_v2 = nullptr; |
| 56 | 52 | F_auth_plugin_psk_key_get_v2 psk_key_get_v2 = nullptr; |
| 57 | 53 | |
| 54 | + ConfigFileParser &confFileParser; | |
| 55 | + | |
| 58 | 56 | void *pluginData = nullptr; |
| 59 | 57 | Logger *logger = nullptr; |
| 58 | + bool initialized = false; | |
| 59 | + bool wanted = false; | |
| 60 | 60 | |
| 61 | - void *loadSymbol(void *handle, const char *symbol); | |
| 61 | + void *loadSymbol(void *handle, const char *symbol) const; | |
| 62 | 62 | public: |
| 63 | - AuthPlugin(); | |
| 63 | + AuthPlugin(ConfigFileParser &confFileParser); | |
| 64 | + AuthPlugin(const AuthPlugin &other) = delete; | |
| 65 | + AuthPlugin(AuthPlugin &&other) = delete; | |
| 66 | + ~AuthPlugin(); | |
| 64 | 67 | |
| 65 | 68 | void loadPlugin(const std::string &pathToSoFile); |
| 66 | - int init(); | |
| 67 | - int cleanup(); | |
| 68 | - int securityInit(bool reloading); | |
| 69 | - int securityCleanup(bool reloading); | |
| 69 | + void init(); | |
| 70 | + void cleanup(); | |
| 71 | + void securityInit(bool reloading); | |
| 72 | + void securityCleanup(bool reloading); | |
| 70 | 73 | AuthResult aclCheck(const std::string &clientid, const std::string &username, const std::string &topic, AclAccess access); |
| 71 | 74 | AuthResult unPwdCheck(const std::string &username, const std::string &password); |
| 72 | 75 | ... | ... |
configfileparser.cpp
0 โ 100644
| 1 | +#include "configfileparser.h" | |
| 2 | + | |
| 3 | +#include <fcntl.h> | |
| 4 | +#include <unistd.h> | |
| 5 | +#include <sstream> | |
| 6 | +#include "fstream" | |
| 7 | + | |
| 8 | +#include "exceptions.h" | |
| 9 | +#include "utils.h" | |
| 10 | +#include <regex> | |
| 11 | + | |
| 12 | + | |
| 13 | +mosquitto_auth_opt::mosquitto_auth_opt(const std::string &key, const std::string &value) | |
| 14 | +{ | |
| 15 | + this->key = strdup(key.c_str()); | |
| 16 | + this->value = strdup(value.c_str()); | |
| 17 | +} | |
| 18 | + | |
| 19 | +mosquitto_auth_opt::mosquitto_auth_opt(mosquitto_auth_opt &&other) | |
| 20 | +{ | |
| 21 | + this->key = other.key; | |
| 22 | + this->value = other.value; | |
| 23 | + other.key = nullptr; | |
| 24 | + other.value = nullptr; | |
| 25 | +} | |
| 26 | + | |
| 27 | +mosquitto_auth_opt::~mosquitto_auth_opt() | |
| 28 | +{ | |
| 29 | + if (key) | |
| 30 | + delete key; | |
| 31 | + if (value) | |
| 32 | + delete value; | |
| 33 | +} | |
| 34 | + | |
| 35 | +AuthOptCompatWrap::AuthOptCompatWrap(const std::unordered_map<std::string, std::string> &authOpts) | |
| 36 | +{ | |
| 37 | + for(auto &pair : authOpts) | |
| 38 | + { | |
| 39 | + mosquitto_auth_opt opt(pair.first, pair.second); | |
| 40 | + optArray.push_back(std::move(opt)); | |
| 41 | + } | |
| 42 | +} | |
| 43 | + | |
| 44 | +ConfigFileParser::ConfigFileParser(const std::string &path) : | |
| 45 | + path(path) | |
| 46 | +{ | |
| 47 | + validKeys.insert("auth_plugin"); | |
| 48 | +} | |
| 49 | + | |
| 50 | +void ConfigFileParser::loadFile() | |
| 51 | +{ | |
| 52 | + if (access(path.c_str(), R_OK) != 0) | |
| 53 | + { | |
| 54 | + std::ostringstream oss; | |
| 55 | + oss << "Error: " << path << " is not there or not readable"; | |
| 56 | + throw ConfigFileException(oss.str()); | |
| 57 | + } | |
| 58 | + | |
| 59 | + std::ifstream infile(path, std::ios::in); | |
| 60 | + | |
| 61 | + if (!infile.is_open()) | |
| 62 | + { | |
| 63 | + std::ostringstream oss; | |
| 64 | + oss << "Error loading " << path; | |
| 65 | + throw ConfigFileException(oss.str()); | |
| 66 | + } | |
| 67 | + | |
| 68 | + std::list<std::string> lines; | |
| 69 | + | |
| 70 | + const std::regex r("^([a-zA-Z0-9_\\-]+) +([a-zA-Z0-9_\\-/\\.]+)$"); | |
| 71 | + | |
| 72 | + // First parse the file and keep the valid lines. | |
| 73 | + for(std::string line; getline(infile, line ); ) | |
| 74 | + { | |
| 75 | + trim(line); | |
| 76 | + | |
| 77 | + if (startsWith(line, "#")) | |
| 78 | + continue; | |
| 79 | + | |
| 80 | + if (line.empty()) | |
| 81 | + continue; | |
| 82 | + | |
| 83 | + std::smatch matches; | |
| 84 | + | |
| 85 | + if (!std::regex_search(line, matches, r) || matches.size() != 3) | |
| 86 | + { | |
| 87 | + std::ostringstream oss; | |
| 88 | + oss << "Line '" << line << "' not in 'key value' format"; | |
| 89 | + throw ConfigFileException(oss.str()); | |
| 90 | + } | |
| 91 | + | |
| 92 | + lines.push_back(line); | |
| 93 | + } | |
| 94 | + | |
| 95 | + authOpts.clear(); | |
| 96 | + authOptCompatWrap.reset(); | |
| 97 | + | |
| 98 | + // Then once we know the config file is valid, process it. | |
| 99 | + for (std::string &line : lines) | |
| 100 | + { | |
| 101 | + std::smatch matches; | |
| 102 | + | |
| 103 | + if (!std::regex_search(line, matches, r) || matches.size() != 3) | |
| 104 | + { | |
| 105 | + throw ConfigFileException("Config parse error at a point that should not be possible."); | |
| 106 | + } | |
| 107 | + | |
| 108 | + std::string key = matches[1].str(); | |
| 109 | + const std::string value = matches[2].str(); | |
| 110 | + | |
| 111 | + const std::string auth_opt_ = "auth_opt_"; | |
| 112 | + if (startsWith(key, auth_opt_)) | |
| 113 | + { | |
| 114 | + key.replace(0, auth_opt_.length(), ""); | |
| 115 | + authOpts[key] = value; | |
| 116 | + } | |
| 117 | + else | |
| 118 | + { | |
| 119 | + auto valid_key_it = validKeys.find(key); | |
| 120 | + if (valid_key_it == validKeys.end()) | |
| 121 | + { | |
| 122 | + std::ostringstream oss; | |
| 123 | + oss << "Config key '" << key << "' is not valid"; | |
| 124 | + throw ConfigFileException(oss.str()); | |
| 125 | + } | |
| 126 | + | |
| 127 | + if (key == "auth_plugin") | |
| 128 | + { | |
| 129 | + this->authPluginPath = value; | |
| 130 | + } | |
| 131 | + } | |
| 132 | + } | |
| 133 | + | |
| 134 | + authOptCompatWrap.reset(new AuthOptCompatWrap(authOpts)); | |
| 135 | +} | |
| 136 | + | |
| 137 | +AuthOptCompatWrap &ConfigFileParser::getAuthOptsCompat() | |
| 138 | +{ | |
| 139 | + return *authOptCompatWrap.get(); | |
| 140 | +} | |
| 141 | + | |
| 142 | + | |
| 143 | + | ... | ... |
configfileparser.h
0 โ 100644
| 1 | +#ifndef CONFIGFILEPARSER_H | |
| 2 | +#define CONFIGFILEPARSER_H | |
| 3 | + | |
| 4 | +#include <string> | |
| 5 | +#include <set> | |
| 6 | +#include <unordered_map> | |
| 7 | +#include <vector> | |
| 8 | +#include <memory> | |
| 9 | + | |
| 10 | +struct mosquitto_auth_opt | |
| 11 | +{ | |
| 12 | + char *key = nullptr; | |
| 13 | + char *value = nullptr; | |
| 14 | + | |
| 15 | + mosquitto_auth_opt(const std::string &key, const std::string &value); | |
| 16 | + mosquitto_auth_opt(mosquitto_auth_opt &&other); | |
| 17 | + mosquitto_auth_opt(const mosquitto_auth_opt &other) = delete; | |
| 18 | + ~mosquitto_auth_opt(); | |
| 19 | +}; | |
| 20 | + | |
| 21 | +struct AuthOptCompatWrap | |
| 22 | +{ | |
| 23 | + std::vector<struct mosquitto_auth_opt> optArray; | |
| 24 | + | |
| 25 | + AuthOptCompatWrap(const std::unordered_map<std::string, std::string> &authOpts); | |
| 26 | + AuthOptCompatWrap(const AuthOptCompatWrap &other) = delete; | |
| 27 | + AuthOptCompatWrap(AuthOptCompatWrap &&other) = delete; | |
| 28 | + | |
| 29 | + struct mosquitto_auth_opt *head() { return &optArray[0]; } | |
| 30 | + int size() { return optArray.size(); } | |
| 31 | +}; | |
| 32 | + | |
| 33 | +class ConfigFileParser | |
| 34 | +{ | |
| 35 | + const std::string path; | |
| 36 | + std::set<std::string> validKeys; | |
| 37 | + std::unordered_map<std::string, std::string> authOpts; | |
| 38 | + std::unique_ptr<AuthOptCompatWrap> authOptCompatWrap; | |
| 39 | + std::string authPluginPath; | |
| 40 | + | |
| 41 | +public: | |
| 42 | + ConfigFileParser(const std::string &path); | |
| 43 | + void loadFile(); | |
| 44 | + AuthOptCompatWrap &getAuthOptsCompat(); | |
| 45 | + | |
| 46 | + std::string getAuthPluginPath() { return authPluginPath; } | |
| 47 | +}; | |
| 48 | + | |
| 49 | +#endif // CONFIGFILEPARSER_H | ... | ... |
exceptions.h
| ... | ... | @@ -22,4 +22,16 @@ public: |
| 22 | 22 | FatalError(const std::string &msg) : std::runtime_error(msg) {} |
| 23 | 23 | }; |
| 24 | 24 | |
| 25 | +class ConfigFileException : public std::runtime_error | |
| 26 | +{ | |
| 27 | +public: | |
| 28 | + ConfigFileException(const std::string &msg) : std::runtime_error(msg) {} | |
| 29 | +}; | |
| 30 | + | |
| 31 | +class AuthPluginException : public std::runtime_error | |
| 32 | +{ | |
| 33 | +public: | |
| 34 | + AuthPluginException(const std::string &msg) : std::runtime_error(msg) {} | |
| 35 | +}; | |
| 36 | + | |
| 25 | 37 | #endif // EXCEPTIONS_H | ... | ... |
main.cpp
| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | |
| 7 | 7 | #include "mainapp.h" |
| 8 | 8 | |
| 9 | -MainApp *mainApp = MainApp::getMainApp(); | |
| 9 | +MainApp *mainApp = nullptr; | |
| 10 | 10 | |
| 11 | 11 | static void signal_handler(int signal) |
| 12 | 12 | { |
| ... | ... | @@ -65,6 +65,7 @@ int main() |
| 65 | 65 | { |
| 66 | 66 | try |
| 67 | 67 | { |
| 68 | + mainApp = MainApp::getMainApp(); | |
| 68 | 69 | check<std::runtime_error>(register_signal_handers()); |
| 69 | 70 | mainApp->start(); |
| 70 | 71 | } | ... | ... |
mainapp.cpp
| ... | ... | @@ -111,7 +111,8 @@ void do_thread_work(ThreadData *threadData) |
| 111 | 111 | MainApp::MainApp() : |
| 112 | 112 | subscriptionStore(new SubscriptionStore()) |
| 113 | 113 | { |
| 114 | - | |
| 114 | + confFileParser.reset(new ConfigFileParser("/home/halfgaar/Projects/FlashMQThings/config.txt")); // TODO: from argv | |
| 115 | + confFileParser->loadFile(); | |
| 115 | 116 | } |
| 116 | 117 | |
| 117 | 118 | MainApp *MainApp::getMainApp() |
| ... | ... | @@ -154,7 +155,7 @@ void MainApp::start() |
| 154 | 155 | |
| 155 | 156 | for (int i = 0; i < NR_OF_THREADS; i++) |
| 156 | 157 | { |
| 157 | - std::shared_ptr<ThreadData> t(new ThreadData(i, subscriptionStore)); | |
| 158 | + std::shared_ptr<ThreadData> t(new ThreadData(i, subscriptionStore, *confFileParser.get())); | |
| 158 | 159 | std::thread thread(do_thread_work, t.get()); |
| 159 | 160 | t->moveThreadHere(std::move(thread)); |
| 160 | 161 | threads.push_back(t); | ... | ... |
mainapp.h
| ... | ... | @@ -16,6 +16,7 @@ |
| 16 | 16 | #include "client.h" |
| 17 | 17 | #include "mqttpacket.h" |
| 18 | 18 | #include "subscriptionstore.h" |
| 19 | +#include "configfileparser.h" | |
| 19 | 20 | |
| 20 | 21 | class MainApp |
| 21 | 22 | { |
| ... | ... | @@ -25,6 +26,7 @@ class MainApp |
| 25 | 26 | bool running = true; |
| 26 | 27 | std::vector<std::shared_ptr<ThreadData>> threads; |
| 27 | 28 | std::shared_ptr<SubscriptionStore> subscriptionStore; |
| 29 | + std::unique_ptr<ConfigFileParser> confFileParser; | |
| 28 | 30 | |
| 29 | 31 | MainApp(); |
| 30 | 32 | public: | ... | ... |
threaddata.cpp
| ... | ... | @@ -2,11 +2,19 @@ |
| 2 | 2 | #include <string> |
| 3 | 3 | #include <sstream> |
| 4 | 4 | |
| 5 | -ThreadData::ThreadData(int threadnr, std::shared_ptr<SubscriptionStore> &subscriptionStore) : | |
| 5 | +ThreadData::ThreadData(int threadnr, std::shared_ptr<SubscriptionStore> &subscriptionStore, ConfigFileParser &confFileParser) : | |
| 6 | 6 | subscriptionStore(subscriptionStore), |
| 7 | + confFileParser(confFileParser), | |
| 8 | + authPlugin(confFileParser), | |
| 7 | 9 | threadnr(threadnr) |
| 8 | 10 | { |
| 11 | + logger = Logger::getInstance(); | |
| 12 | + | |
| 9 | 13 | epollfd = check<std::runtime_error>(epoll_create(999)); |
| 14 | + | |
| 15 | + authPlugin.loadPlugin(confFileParser.getAuthPluginPath()); | |
| 16 | + authPlugin.init(); | |
| 17 | + authPlugin.securityInit(false); | |
| 10 | 18 | } |
| 11 | 19 | |
| 12 | 20 | void ThreadData::moveThreadHere(std::thread &&thread) |
| ... | ... | @@ -92,5 +100,18 @@ bool ThreadData::doKeepAliveCheck() |
| 92 | 100 | return true; |
| 93 | 101 | } |
| 94 | 102 | |
| 103 | +void ThreadData::reload() | |
| 104 | +{ | |
| 105 | + try | |
| 106 | + { | |
| 107 | + authPlugin.securityCleanup(true); | |
| 108 | + authPlugin.securityInit(true); | |
| 109 | + } | |
| 110 | + catch (AuthPluginException &ex) | |
| 111 | + { | |
| 112 | + logger->logf(LOG_ERR, "Error reloading auth plugin: %s. Security checks will now fail, because we don't know the status of the plugin anymore.", ex.what()); | |
| 113 | + } | |
| 114 | +} | |
| 115 | + | |
| 95 | 116 | |
| 96 | 117 | ... | ... |
threaddata.h
| ... | ... | @@ -16,14 +16,18 @@ |
| 16 | 16 | #include "client.h" |
| 17 | 17 | #include "subscriptionstore.h" |
| 18 | 18 | #include "utils.h" |
| 19 | - | |
| 20 | - | |
| 19 | +#include "configfileparser.h" | |
| 20 | +#include "authplugin.h" | |
| 21 | +#include "logger.h" | |
| 21 | 22 | |
| 22 | 23 | class ThreadData |
| 23 | 24 | { |
| 24 | 25 | std::unordered_map<int, Client_p> clients_by_fd; |
| 25 | 26 | std::mutex clients_by_fd_mutex; |
| 26 | 27 | std::shared_ptr<SubscriptionStore> subscriptionStore; |
| 28 | + ConfigFileParser &confFileParser; | |
| 29 | + AuthPlugin authPlugin; | |
| 30 | + Logger *logger; | |
| 27 | 31 | |
| 28 | 32 | public: |
| 29 | 33 | bool running = true; |
| ... | ... | @@ -31,7 +35,9 @@ public: |
| 31 | 35 | int threadnr = 0; |
| 32 | 36 | int epollfd = 0; |
| 33 | 37 | |
| 34 | - ThreadData(int threadnr, std::shared_ptr<SubscriptionStore> &subscriptionStore); | |
| 38 | + ThreadData(int threadnr, std::shared_ptr<SubscriptionStore> &subscriptionStore, ConfigFileParser &confFileParser); | |
| 39 | + ThreadData(const ThreadData &other) = delete; | |
| 40 | + ThreadData(ThreadData &&other) = delete; | |
| 35 | 41 | |
| 36 | 42 | void moveThreadHere(std::thread &&thread); |
| 37 | 43 | void quit(); |
| ... | ... | @@ -42,6 +48,7 @@ public: |
| 42 | 48 | std::shared_ptr<SubscriptionStore> &getSubscriptionStore(); |
| 43 | 49 | |
| 44 | 50 | bool doKeepAliveCheck(); |
| 51 | + void reload(); | |
| 45 | 52 | }; |
| 46 | 53 | |
| 47 | 54 | #endif // THREADDATA_H | ... | ... |
utils.cpp
| 1 | 1 | #include "utils.h" |
| 2 | 2 | |
| 3 | - | |
| 3 | +#include <algorithm> | |
| 4 | 4 | |
| 5 | 5 | std::list<std::__cxx11::string> split(const std::string &input, const char sep, size_t max, bool keep_empty_parts) |
| 6 | 6 | { |
| ... | ... | @@ -143,3 +143,28 @@ std::vector<std::string> splitToVector(const std::string &input, const char sep, |
| 143 | 143 | list.push_back(input.substr(start, std::string::npos)); |
| 144 | 144 | return list; |
| 145 | 145 | } |
| 146 | + | |
| 147 | +void ltrim(std::string &s) | |
| 148 | +{ | |
| 149 | + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { | |
| 150 | + return !std::isspace(ch); | |
| 151 | + })); | |
| 152 | +} | |
| 153 | + | |
| 154 | +void rtrim(std::string &s) | |
| 155 | +{ | |
| 156 | + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { | |
| 157 | + return !std::isspace(ch); | |
| 158 | + }).base(), s.end()); | |
| 159 | +} | |
| 160 | + | |
| 161 | +void trim(std::string &s) | |
| 162 | +{ | |
| 163 | + ltrim(s); | |
| 164 | + rtrim(s); | |
| 165 | +} | |
| 166 | + | |
| 167 | +bool startsWith(const std::string &s, const std::string &needle) | |
| 168 | +{ | |
| 169 | + return s.find(needle) == 0; | |
| 170 | +} | ... | ... |
utils.h
| ... | ... | @@ -7,6 +7,7 @@ |
| 7 | 7 | #include <list> |
| 8 | 8 | #include <limits> |
| 9 | 9 | #include <vector> |
| 10 | +#include <algorithm> | |
| 10 | 11 | |
| 11 | 12 | template<typename T> int check(int rc) |
| 12 | 13 | { |
| ... | ... | @@ -31,4 +32,10 @@ bool strContains(const std::string &s, const std::string &needle); |
| 31 | 32 | |
| 32 | 33 | bool isValidPublishPath(const std::string &s); |
| 33 | 34 | |
| 35 | +void ltrim(std::string &s); | |
| 36 | +void rtrim(std::string &s); | |
| 37 | +void trim(std::string &s); | |
| 38 | +bool startsWith(const std::string &s, const std::string &needle); | |
| 39 | + | |
| 40 | + | |
| 34 | 41 | #endif // UTILS_H | ... | ... |