Commit 1b9f09780e1ae659ef0e9b8086b173da2365a5a1
1 parent
4315fb5b
Start of auth plugin.
I kind of need a config file parser first, so I'm going to make that.
Showing
5 changed files
with
207 additions
and
1 deletions
CMakeLists.txt
| @@ -5,6 +5,7 @@ project(FlashMQ LANGUAGES CXX) | @@ -5,6 +5,7 @@ project(FlashMQ LANGUAGES CXX) | ||
| 5 | set(CMAKE_CXX_STANDARD 11) | 5 | set(CMAKE_CXX_STANDARD 11) |
| 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) | 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) |
| 7 | 7 | ||
| 8 | +SET(CMAKE_CXX_FLAGS "-rdynamic") | ||
| 8 | 9 | ||
| 9 | add_executable(FlashMQ | 10 | add_executable(FlashMQ |
| 10 | mainapp.cpp | 11 | mainapp.cpp |
| @@ -21,6 +22,7 @@ add_executable(FlashMQ | @@ -21,6 +22,7 @@ add_executable(FlashMQ | ||
| 21 | retainedmessage.cpp | 22 | retainedmessage.cpp |
| 22 | cirbuf.cpp | 23 | cirbuf.cpp |
| 23 | logger.cpp | 24 | logger.cpp |
| 25 | + authplugin.cpp | ||
| 24 | ) | 26 | ) |
| 25 | 27 | ||
| 26 | -target_link_libraries(FlashMQ pthread) | 28 | +target_link_libraries(FlashMQ pthread dl) |
FlashMQTests/FlashMQTests.pro
| @@ -26,6 +26,7 @@ SOURCES += tst_maintests.cpp \ | @@ -26,6 +26,7 @@ SOURCES += tst_maintests.cpp \ | ||
| 26 | ../types.cpp \ | 26 | ../types.cpp \ |
| 27 | ../utils.cpp \ | 27 | ../utils.cpp \ |
| 28 | ../logger.cpp \ | 28 | ../logger.cpp \ |
| 29 | + ../authplugin.cpp \ | ||
| 29 | mainappthread.cpp \ | 30 | mainappthread.cpp \ |
| 30 | twoclienttestcontext.cpp | 31 | twoclienttestcontext.cpp |
| 31 | 32 | ||
| @@ -44,5 +45,10 @@ HEADERS += \ | @@ -44,5 +45,10 @@ HEADERS += \ | ||
| 44 | ../types.h \ | 45 | ../types.h \ |
| 45 | ../utils.h \ | 46 | ../utils.h \ |
| 46 | ../logger.h \ | 47 | ../logger.h \ |
| 48 | + ../authplugin.h \ | ||
| 47 | mainappthread.h \ | 49 | mainappthread.h \ |
| 48 | twoclienttestcontext.h | 50 | twoclienttestcontext.h |
| 51 | + | ||
| 52 | +LIBS += -ldl | ||
| 53 | + | ||
| 54 | +QMAKE_LFLAGS += -rdynamic |
authplugin.cpp
0 → 100644
| 1 | +#include "authplugin.h" | ||
| 2 | + | ||
| 3 | +#include <unistd.h> | ||
| 4 | +#include <fcntl.h> | ||
| 5 | +#include <sstream> | ||
| 6 | +#include <dlfcn.h> | ||
| 7 | + | ||
| 8 | +#include "exceptions.h" | ||
| 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, ...) | ||
| 15 | +{ | ||
| 16 | + Logger *logger = Logger::getInstance(); | ||
| 17 | + va_list valist; | ||
| 18 | + va_start(valist, fmt); | ||
| 19 | + logger->logf(level, fmt); | ||
| 20 | + va_end(valist); | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +AuthPlugin::AuthPlugin() // our configuration object as param | ||
| 25 | +{ | ||
| 26 | + logger = Logger::getInstance(); | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +void *AuthPlugin::loadSymbol(void *handle, const char *symbol) | ||
| 30 | +{ | ||
| 31 | + void *r = dlsym(handle, symbol); | ||
| 32 | + | ||
| 33 | + if (r == NULL) | ||
| 34 | + { | ||
| 35 | + std::string errmsg(dlerror()); | ||
| 36 | + throw FatalError(errmsg); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + return r; | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +void AuthPlugin::loadPlugin(const std::string &pathToSoFile) | ||
| 43 | +{ | ||
| 44 | + logger->logf(LOG_INFO, "Loading auth plugin %s", pathToSoFile.c_str()); | ||
| 45 | + | ||
| 46 | + if (access(pathToSoFile.c_str(), R_OK) != 0) | ||
| 47 | + { | ||
| 48 | + std::ostringstream oss; | ||
| 49 | + oss << "Error loading auth plugin: The file " << pathToSoFile << " is not there or not readable"; | ||
| 50 | + throw FatalError(oss.str()); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + void *r = dlopen(pathToSoFile.c_str(), RTLD_NOW|RTLD_GLOBAL); | ||
| 54 | + | ||
| 55 | + if (r == NULL) | ||
| 56 | + { | ||
| 57 | + std::string errmsg(dlerror()); | ||
| 58 | + throw FatalError(errmsg); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + version = (F_auth_plugin_version)loadSymbol(r, "mosquitto_auth_plugin_version"); | ||
| 62 | + | ||
| 63 | + if (version() != 2) | ||
| 64 | + { | ||
| 65 | + throw FatalError("Only Mosquitto plugin version 2 is supported at this time."); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + init_v2 = (F_auth_plugin_init_v2)loadSymbol(r, "mosquitto_auth_plugin_init"); | ||
| 69 | + cleanup_v2 = (F_auth_plugin_cleanup_v2)loadSymbol(r, "mosquitto_auth_plugin_cleanup"); | ||
| 70 | + security_init_v2 = (F_auth_plugin_security_init_v2)loadSymbol(r, "mosquitto_auth_security_init"); | ||
| 71 | + security_cleanup_v2 = (F_auth_plugin_security_cleanup_v2)loadSymbol(r, "mosquitto_auth_security_cleanup"); | ||
| 72 | + 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"); | ||
| 74 | + psk_key_get_v2 = (F_auth_plugin_psk_key_get_v2)loadSymbol(r, "mosquitto_auth_psk_key_get"); | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +int AuthPlugin::init() | ||
| 78 | +{ | ||
| 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; | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +int AuthPlugin::cleanup() | ||
| 86 | +{ | ||
| 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); | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +int AuthPlugin::securityInit(bool reloading) | ||
| 93 | +{ | ||
| 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); | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +int AuthPlugin::securityCleanup(bool reloading) | ||
| 100 | +{ | ||
| 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); | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +AuthResult AuthPlugin::aclCheck(const std::string &clientid, const std::string &username, const std::string &topic, AclAccess access) | ||
| 107 | +{ | ||
| 108 | + 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); | ||
| 110 | +} | ||
| 111 | + | ||
| 112 | +AuthResult AuthPlugin::unPwdCheck(const std::string &username, const std::string &password) | ||
| 113 | +{ | ||
| 114 | + int result = unpwd_check_v2(pluginData, username.c_str(), password.c_str()); | ||
| 115 | + return static_cast<AuthResult>(result); | ||
| 116 | +} | ||
| 117 | + | ||
| 118 | + |
authplugin.h
0 → 100644
| 1 | +#ifndef AUTHPLUGIN_H | ||
| 2 | +#define AUTHPLUGIN_H | ||
| 3 | + | ||
| 4 | +#include <string> | ||
| 5 | +#include <cstring> | ||
| 6 | + | ||
| 7 | +#include "logger.h" | ||
| 8 | + | ||
| 9 | +// Compatible with Mosquitto | ||
| 10 | +enum class AclAccess | ||
| 11 | +{ | ||
| 12 | + none = 0, | ||
| 13 | + read = 1, | ||
| 14 | + write = 2 | ||
| 15 | +}; | ||
| 16 | + | ||
| 17 | +// Compatible with Mosquitto | ||
| 18 | +enum class AuthResult | ||
| 19 | +{ | ||
| 20 | + success = 0, | ||
| 21 | + acl_denied = 12, | ||
| 22 | + login_denied = 11, | ||
| 23 | + error = 13 | ||
| 24 | +}; | ||
| 25 | + | ||
| 26 | +struct mosquitto_auth_opt { | ||
| 27 | + char *key; | ||
| 28 | + char *value; | ||
| 29 | +}; | ||
| 30 | + | ||
| 31 | +typedef int (*F_auth_plugin_version)(void); | ||
| 32 | + | ||
| 33 | +typedef int (*F_auth_plugin_init_v2)(void **, struct mosquitto_auth_opt *, int); | ||
| 34 | +typedef int (*F_auth_plugin_cleanup_v2)(void *, struct mosquitto_auth_opt *, int); | ||
| 35 | +typedef int (*F_auth_plugin_security_init_v2)(void *, struct mosquitto_auth_opt *, int, bool); | ||
| 36 | +typedef int (*F_auth_plugin_security_cleanup_v2)(void *, struct mosquitto_auth_opt *, int, bool); | ||
| 37 | +typedef int (*F_auth_plugin_acl_check_v2)(void *, const char *, const char *, const char *, int); | ||
| 38 | +typedef int (*F_auth_plugin_unpwd_check_v2)(void *, const char *, const char *); | ||
| 39 | +typedef int (*F_auth_plugin_psk_key_get_v2)(void *, const char *, const char *, char *, int); | ||
| 40 | + | ||
| 41 | +extern "C" | ||
| 42 | +{ | ||
| 43 | + // Gets called by the plugin, so it needs to exist, globally | ||
| 44 | + void mosquitto_log_printf(int level, const char *fmt, ...); | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +class AuthPlugin | ||
| 48 | +{ | ||
| 49 | + F_auth_plugin_version version = nullptr; | ||
| 50 | + F_auth_plugin_init_v2 init_v2 = nullptr; | ||
| 51 | + F_auth_plugin_cleanup_v2 cleanup_v2 = nullptr; | ||
| 52 | + F_auth_plugin_security_init_v2 security_init_v2 = nullptr; | ||
| 53 | + F_auth_plugin_security_cleanup_v2 security_cleanup_v2 = nullptr; | ||
| 54 | + F_auth_plugin_acl_check_v2 acl_check_v2 = nullptr; | ||
| 55 | + F_auth_plugin_unpwd_check_v2 unpwd_check_v2 = nullptr; | ||
| 56 | + F_auth_plugin_psk_key_get_v2 psk_key_get_v2 = nullptr; | ||
| 57 | + | ||
| 58 | + void *pluginData = nullptr; | ||
| 59 | + Logger *logger = nullptr; | ||
| 60 | + | ||
| 61 | + void *loadSymbol(void *handle, const char *symbol); | ||
| 62 | +public: | ||
| 63 | + AuthPlugin(); | ||
| 64 | + | ||
| 65 | + void loadPlugin(const std::string &pathToSoFile); | ||
| 66 | + int init(); | ||
| 67 | + int cleanup(); | ||
| 68 | + int securityInit(bool reloading); | ||
| 69 | + int securityCleanup(bool reloading); | ||
| 70 | + 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); | ||
| 72 | + | ||
| 73 | +}; | ||
| 74 | + | ||
| 75 | +#endif // AUTHPLUGIN_H |
exceptions.h
| @@ -16,5 +16,10 @@ public: | @@ -16,5 +16,10 @@ public: | ||
| 16 | NotImplementedException(const std::string &msg) : std::runtime_error(msg) {} | 16 | NotImplementedException(const std::string &msg) : std::runtime_error(msg) {} |
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| 19 | +class FatalError : public std::runtime_error | ||
| 20 | +{ | ||
| 21 | +public: | ||
| 22 | + FatalError(const std::string &msg) : std::runtime_error(msg) {} | ||
| 23 | +}; | ||
| 19 | 24 | ||
| 20 | #endif // EXCEPTIONS_H | 25 | #endif // EXCEPTIONS_H |