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
| @@ -23,6 +23,7 @@ add_executable(FlashMQ | @@ -23,6 +23,7 @@ add_executable(FlashMQ | ||
| 23 | cirbuf.cpp | 23 | cirbuf.cpp |
| 24 | logger.cpp | 24 | logger.cpp |
| 25 | authplugin.cpp | 25 | authplugin.cpp |
| 26 | + configfileparser.cpp | ||
| 26 | ) | 27 | ) |
| 27 | 28 | ||
| 28 | target_link_libraries(FlashMQ pthread dl) | 29 | target_link_libraries(FlashMQ pthread dl) |
authplugin.cpp
| @@ -7,10 +7,6 @@ | @@ -7,10 +7,6 @@ | ||
| 7 | 7 | ||
| 8 | #include "exceptions.h" | 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 | void mosquitto_log_printf(int level, const char *fmt, ...) | 10 | void mosquitto_log_printf(int level, const char *fmt, ...) |
| 15 | { | 11 | { |
| 16 | Logger *logger = Logger::getInstance(); | 12 | Logger *logger = Logger::getInstance(); |
| @@ -21,12 +17,18 @@ void mosquitto_log_printf(int level, const char *fmt, ...) | @@ -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 | logger = Logger::getInstance(); | 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 | void *r = dlsym(handle, symbol); | 33 | void *r = dlsym(handle, symbol); |
| 32 | 34 | ||
| @@ -41,8 +43,14 @@ void *AuthPlugin::loadSymbol(void *handle, const char *symbol) | @@ -41,8 +43,14 @@ void *AuthPlugin::loadSymbol(void *handle, const char *symbol) | ||
| 41 | 43 | ||
| 42 | void AuthPlugin::loadPlugin(const std::string &pathToSoFile) | 44 | void AuthPlugin::loadPlugin(const std::string &pathToSoFile) |
| 43 | { | 45 | { |
| 46 | + if (pathToSoFile.empty()) | ||
| 47 | + return; | ||
| 48 | + | ||
| 44 | logger->logf(LOG_INFO, "Loading auth plugin %s", pathToSoFile.c_str()); | 49 | logger->logf(LOG_INFO, "Loading auth plugin %s", pathToSoFile.c_str()); |
| 45 | 50 | ||
| 51 | + initialized = false; | ||
| 52 | + wanted = true; | ||
| 53 | + | ||
| 46 | if (access(pathToSoFile.c_str(), R_OK) != 0) | 54 | if (access(pathToSoFile.c_str(), R_OK) != 0) |
| 47 | { | 55 | { |
| 48 | std::ostringstream oss; | 56 | std::ostringstream oss; |
| @@ -72,47 +80,105 @@ void AuthPlugin::loadPlugin(const std::string &pathToSoFile) | @@ -72,47 +80,105 @@ void AuthPlugin::loadPlugin(const std::string &pathToSoFile) | ||
| 72 | acl_check_v2 = (F_auth_plugin_acl_check_v2)loadSymbol(r, "mosquitto_auth_acl_check"); | 80 | acl_check_v2 = (F_auth_plugin_acl_check_v2)loadSymbol(r, "mosquitto_auth_acl_check"); |
| 73 | unpwd_check_v2 = (F_auth_plugin_unpwd_check_v2)loadSymbol(r, "mosquitto_auth_unpwd_check"); | 81 | unpwd_check_v2 = (F_auth_plugin_unpwd_check_v2)loadSymbol(r, "mosquitto_auth_unpwd_check"); |
| 74 | psk_key_get_v2 = (F_auth_plugin_psk_key_get_v2)loadSymbol(r, "mosquitto_auth_psk_key_get"); | 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 | AuthResult AuthPlugin::aclCheck(const std::string &clientid, const std::string &username, const std::string &topic, AclAccess access) | 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 | int result = acl_check_v2(pluginData, clientid.c_str(), username.c_str(), topic.c_str(), static_cast<int>(access)); | 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 | AuthResult AuthPlugin::unPwdCheck(const std::string &username, const std::string &password) | 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 | int result = unpwd_check_v2(pluginData, username.c_str(), password.c_str()); | 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,6 +5,7 @@ | ||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | 6 | ||
| 7 | #include "logger.h" | 7 | #include "logger.h" |
| 8 | +#include "configfileparser.h" | ||
| 8 | 9 | ||
| 9 | // Compatible with Mosquitto | 10 | // Compatible with Mosquitto |
| 10 | enum class AclAccess | 11 | enum class AclAccess |
| @@ -23,11 +24,6 @@ enum class AuthResult | @@ -23,11 +24,6 @@ enum class AuthResult | ||
| 23 | error = 13 | 24 | error = 13 |
| 24 | }; | 25 | }; |
| 25 | 26 | ||
| 26 | -struct mosquitto_auth_opt { | ||
| 27 | - char *key; | ||
| 28 | - char *value; | ||
| 29 | -}; | ||
| 30 | - | ||
| 31 | typedef int (*F_auth_plugin_version)(void); | 27 | typedef int (*F_auth_plugin_version)(void); |
| 32 | 28 | ||
| 33 | typedef int (*F_auth_plugin_init_v2)(void **, struct mosquitto_auth_opt *, int); | 29 | typedef int (*F_auth_plugin_init_v2)(void **, struct mosquitto_auth_opt *, int); |
| @@ -55,18 +51,25 @@ class AuthPlugin | @@ -55,18 +51,25 @@ class AuthPlugin | ||
| 55 | F_auth_plugin_unpwd_check_v2 unpwd_check_v2 = nullptr; | 51 | F_auth_plugin_unpwd_check_v2 unpwd_check_v2 = nullptr; |
| 56 | F_auth_plugin_psk_key_get_v2 psk_key_get_v2 = nullptr; | 52 | F_auth_plugin_psk_key_get_v2 psk_key_get_v2 = nullptr; |
| 57 | 53 | ||
| 54 | + ConfigFileParser &confFileParser; | ||
| 55 | + | ||
| 58 | void *pluginData = nullptr; | 56 | void *pluginData = nullptr; |
| 59 | Logger *logger = nullptr; | 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 | public: | 62 | public: |
| 63 | - AuthPlugin(); | 63 | + AuthPlugin(ConfigFileParser &confFileParser); |
| 64 | + AuthPlugin(const AuthPlugin &other) = delete; | ||
| 65 | + AuthPlugin(AuthPlugin &&other) = delete; | ||
| 66 | + ~AuthPlugin(); | ||
| 64 | 67 | ||
| 65 | void loadPlugin(const std::string &pathToSoFile); | 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 | AuthResult aclCheck(const std::string &clientid, const std::string &username, const std::string &topic, AclAccess access); | 73 | AuthResult aclCheck(const std::string &clientid, const std::string &username, const std::string &topic, AclAccess access); |
| 71 | AuthResult unPwdCheck(const std::string &username, const std::string &password); | 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,4 +22,16 @@ public: | ||
| 22 | FatalError(const std::string &msg) : std::runtime_error(msg) {} | 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 | #endif // EXCEPTIONS_H | 37 | #endif // EXCEPTIONS_H |
main.cpp
| @@ -6,7 +6,7 @@ | @@ -6,7 +6,7 @@ | ||
| 6 | 6 | ||
| 7 | #include "mainapp.h" | 7 | #include "mainapp.h" |
| 8 | 8 | ||
| 9 | -MainApp *mainApp = MainApp::getMainApp(); | 9 | +MainApp *mainApp = nullptr; |
| 10 | 10 | ||
| 11 | static void signal_handler(int signal) | 11 | static void signal_handler(int signal) |
| 12 | { | 12 | { |
| @@ -65,6 +65,7 @@ int main() | @@ -65,6 +65,7 @@ int main() | ||
| 65 | { | 65 | { |
| 66 | try | 66 | try |
| 67 | { | 67 | { |
| 68 | + mainApp = MainApp::getMainApp(); | ||
| 68 | check<std::runtime_error>(register_signal_handers()); | 69 | check<std::runtime_error>(register_signal_handers()); |
| 69 | mainApp->start(); | 70 | mainApp->start(); |
| 70 | } | 71 | } |
mainapp.cpp
| @@ -111,7 +111,8 @@ void do_thread_work(ThreadData *threadData) | @@ -111,7 +111,8 @@ void do_thread_work(ThreadData *threadData) | ||
| 111 | MainApp::MainApp() : | 111 | MainApp::MainApp() : |
| 112 | subscriptionStore(new SubscriptionStore()) | 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 | MainApp *MainApp::getMainApp() | 118 | MainApp *MainApp::getMainApp() |
| @@ -154,7 +155,7 @@ void MainApp::start() | @@ -154,7 +155,7 @@ void MainApp::start() | ||
| 154 | 155 | ||
| 155 | for (int i = 0; i < NR_OF_THREADS; i++) | 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 | std::thread thread(do_thread_work, t.get()); | 159 | std::thread thread(do_thread_work, t.get()); |
| 159 | t->moveThreadHere(std::move(thread)); | 160 | t->moveThreadHere(std::move(thread)); |
| 160 | threads.push_back(t); | 161 | threads.push_back(t); |
mainapp.h
| @@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
| 16 | #include "client.h" | 16 | #include "client.h" |
| 17 | #include "mqttpacket.h" | 17 | #include "mqttpacket.h" |
| 18 | #include "subscriptionstore.h" | 18 | #include "subscriptionstore.h" |
| 19 | +#include "configfileparser.h" | ||
| 19 | 20 | ||
| 20 | class MainApp | 21 | class MainApp |
| 21 | { | 22 | { |
| @@ -25,6 +26,7 @@ class MainApp | @@ -25,6 +26,7 @@ class MainApp | ||
| 25 | bool running = true; | 26 | bool running = true; |
| 26 | std::vector<std::shared_ptr<ThreadData>> threads; | 27 | std::vector<std::shared_ptr<ThreadData>> threads; |
| 27 | std::shared_ptr<SubscriptionStore> subscriptionStore; | 28 | std::shared_ptr<SubscriptionStore> subscriptionStore; |
| 29 | + std::unique_ptr<ConfigFileParser> confFileParser; | ||
| 28 | 30 | ||
| 29 | MainApp(); | 31 | MainApp(); |
| 30 | public: | 32 | public: |
threaddata.cpp
| @@ -2,11 +2,19 @@ | @@ -2,11 +2,19 @@ | ||
| 2 | #include <string> | 2 | #include <string> |
| 3 | #include <sstream> | 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 | subscriptionStore(subscriptionStore), | 6 | subscriptionStore(subscriptionStore), |
| 7 | + confFileParser(confFileParser), | ||
| 8 | + authPlugin(confFileParser), | ||
| 7 | threadnr(threadnr) | 9 | threadnr(threadnr) |
| 8 | { | 10 | { |
| 11 | + logger = Logger::getInstance(); | ||
| 12 | + | ||
| 9 | epollfd = check<std::runtime_error>(epoll_create(999)); | 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 | void ThreadData::moveThreadHere(std::thread &&thread) | 20 | void ThreadData::moveThreadHere(std::thread &&thread) |
| @@ -92,5 +100,18 @@ bool ThreadData::doKeepAliveCheck() | @@ -92,5 +100,18 @@ bool ThreadData::doKeepAliveCheck() | ||
| 92 | return true; | 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,14 +16,18 @@ | ||
| 16 | #include "client.h" | 16 | #include "client.h" |
| 17 | #include "subscriptionstore.h" | 17 | #include "subscriptionstore.h" |
| 18 | #include "utils.h" | 18 | #include "utils.h" |
| 19 | - | ||
| 20 | - | 19 | +#include "configfileparser.h" |
| 20 | +#include "authplugin.h" | ||
| 21 | +#include "logger.h" | ||
| 21 | 22 | ||
| 22 | class ThreadData | 23 | class ThreadData |
| 23 | { | 24 | { |
| 24 | std::unordered_map<int, Client_p> clients_by_fd; | 25 | std::unordered_map<int, Client_p> clients_by_fd; |
| 25 | std::mutex clients_by_fd_mutex; | 26 | std::mutex clients_by_fd_mutex; |
| 26 | std::shared_ptr<SubscriptionStore> subscriptionStore; | 27 | std::shared_ptr<SubscriptionStore> subscriptionStore; |
| 28 | + ConfigFileParser &confFileParser; | ||
| 29 | + AuthPlugin authPlugin; | ||
| 30 | + Logger *logger; | ||
| 27 | 31 | ||
| 28 | public: | 32 | public: |
| 29 | bool running = true; | 33 | bool running = true; |
| @@ -31,7 +35,9 @@ public: | @@ -31,7 +35,9 @@ public: | ||
| 31 | int threadnr = 0; | 35 | int threadnr = 0; |
| 32 | int epollfd = 0; | 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 | void moveThreadHere(std::thread &&thread); | 42 | void moveThreadHere(std::thread &&thread); |
| 37 | void quit(); | 43 | void quit(); |
| @@ -42,6 +48,7 @@ public: | @@ -42,6 +48,7 @@ public: | ||
| 42 | std::shared_ptr<SubscriptionStore> &getSubscriptionStore(); | 48 | std::shared_ptr<SubscriptionStore> &getSubscriptionStore(); |
| 43 | 49 | ||
| 44 | bool doKeepAliveCheck(); | 50 | bool doKeepAliveCheck(); |
| 51 | + void reload(); | ||
| 45 | }; | 52 | }; |
| 46 | 53 | ||
| 47 | #endif // THREADDATA_H | 54 | #endif // THREADDATA_H |
utils.cpp
| 1 | #include "utils.h" | 1 | #include "utils.h" |
| 2 | 2 | ||
| 3 | - | 3 | +#include <algorithm> |
| 4 | 4 | ||
| 5 | std::list<std::__cxx11::string> split(const std::string &input, const char sep, size_t max, bool keep_empty_parts) | 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,3 +143,28 @@ std::vector<std::string> splitToVector(const std::string &input, const char sep, | ||
| 143 | list.push_back(input.substr(start, std::string::npos)); | 143 | list.push_back(input.substr(start, std::string::npos)); |
| 144 | return list; | 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,6 +7,7 @@ | ||
| 7 | #include <list> | 7 | #include <list> |
| 8 | #include <limits> | 8 | #include <limits> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | +#include <algorithm> | ||
| 10 | 11 | ||
| 11 | template<typename T> int check(int rc) | 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,4 +32,10 @@ bool strContains(const std::string &s, const std::string &needle); | ||
| 31 | 32 | ||
| 32 | bool isValidPublishPath(const std::string &s); | 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 | #endif // UTILS_H | 41 | #endif // UTILS_H |