diff --git a/src/ebusd/datahandler.cpp b/src/ebusd/datahandler.cpp index babe6419..9648f6ed 100644 --- a/src/ebusd/datahandler.cpp +++ b/src/ebusd/datahandler.cpp @@ -50,10 +50,11 @@ const struct argp_child* datahandler_getargs() { return NULL; } -bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list& handlers) { +bool datahandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages, + list& handlers) { bool success = true; #ifdef HAVE_MQTT - DataHandler* handler = mqtthandler_register(busHandler, messages); + DataHandler* handler = mqtthandler_register(userInfo, busHandler, messages); if (handler) { handlers.push_back(handler); } else { @@ -64,7 +65,9 @@ bool datahandler_register(BusHandler* busHandler, MessageMap* messages, listhasLevel(m_levels)) { + m_updatedMessages[message]++; + } } } // namespace ebusd diff --git a/src/ebusd/datahandler.h b/src/ebusd/datahandler.h index 4766db03..1967a835 100644 --- a/src/ebusd/datahandler.h +++ b/src/ebusd/datahandler.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "ebusd/bushandler.h" #include "lib/ebus/message.h" @@ -36,6 +37,7 @@ namespace ebusd { using std::list; using std::map; +class UserInfo; class DataHandler; /** @@ -46,12 +48,48 @@ const struct argp_child* datahandler_getargs(); /** * Registration function that is called once during initialization. + * @param userInfo the @a UserInfo instance. * @param busHandler the @a BusHandler instance. * @param messages the @a MessageMap instance. * @param handlers the @a list to which new @a DataHandler instances shall be added. * @return true if registration was successful. */ -bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list& handlers); +bool datahandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages, + list& handlers); + + +/** + * Helper interface for user authentication. + */ +class UserInfo { + public: + /** + * Destructor. + */ + virtual ~UserInfo() {} + + /** + * Check whether the specified user exists. + * @param user the user name. + * @return whether the user exists. + */ + virtual bool hasUser(const string user) = 0; // abstract + + /** + * Check whether the secret string matches the one of the specified user. + * @param user the user name. + * @param secret the secret to check. + * @return whether the secret string is valid. + */ + virtual bool checkSecret(const string user, const string secret) = 0; // abstract + + /** + * Get the access levels associated with the specified user. + * @param user the user name, or empty for default levels. + * @return the access levels separated by semicolon. + */ + virtual string getLevels(const string user) = 0; // abstract +}; /** @@ -95,8 +133,12 @@ class DataSink : virtual public DataHandler { public: /** * Constructor. + * @param userInfo the @a UserInfo instance. + * @param user the user name for determining the allowed access levels (fall back to default levels). */ - DataSink() {} + DataSink(UserInfo* userInfo, string user) { + m_levels = userInfo->getLevels(userInfo->hasUser(user) ? user : ""); + } /** * Destructor. @@ -114,6 +156,9 @@ class DataSink : virtual public DataHandler { protected: + /** the allowed access levels. */ + string m_levels; + /** a map of updated @p Message instances. */ map m_updatedMessages; }; diff --git a/src/ebusd/mqtthandler.cpp b/src/ebusd/mqtthandler.cpp index 1b2aff9e..9c368cf7 100644 --- a/src/ebusd/mqtthandler.cpp +++ b/src/ebusd/mqtthandler.cpp @@ -165,8 +165,8 @@ const struct argp_child* mqtthandler_getargs() { return &g_mqtt_argp_child; } -DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages) { - return new MqttHandler(busHandler, messages); +DataHandler* mqtthandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages) { + return new MqttHandler(userInfo, busHandler, messages); } /** the known topic column names. */ @@ -177,7 +177,7 @@ static const char* columnNames[] = { }; /** the known topic column IDs. */ -static const size_t columnIds[] = { +static const column_t columnIds[] = { COLUMN_CIRCUIT, COLUMN_NAME, COLUMN_FIELDS, @@ -194,24 +194,25 @@ static const size_t columnCount = sizeof(columnNames) / sizeof(char*); * @param cols the @a vector to which the column parts shall be added. * @return true on success, false on malformed topic template. */ -bool parseTopic(const string topic, vector &strs, vector &cols) { +bool parseTopic(const string topic, vector &strs, vector &cols) { size_t lastpos = 0; size_t end = topic.length(); vector columns; for (size_t pos=topic.find('%', lastpos); pos != string::npos; ) { - size_t col = columnCount; + size_t idx = columnCount; size_t len = 0; for (size_t i = 0; i < columnCount; i++) { len = strlen(columnNames[i]); if (topic.substr(pos+1, len) == columnNames[i]) { - col = columnIds[i]; + idx = i; break; } } - if (col == columnCount) { + if (idx== columnCount) { return false; } - for (vector::iterator it=cols.begin(); it != cols.end(); it++) { + column_t col = columnIds[idx]; + for (vector::iterator it=cols.begin(); it != cols.end(); it++) { if (*it == col) { return false; // duplicate column } @@ -259,8 +260,8 @@ void on_connect( } -MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages) - : DataSink(), DataSource(busHandler), Thread(), m_messages(messages), m_connected(false) { +MqttHandler::MqttHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages) + : DataSink(userInfo, "mqtt"), DataSource(busHandler), Thread(), m_messages(messages), m_connected(false) { bool enabled = g_port != 0; m_publishByField = false; m_mosquitto = NULL; @@ -396,17 +397,16 @@ void MqttHandler::notifyTopic(string topic, string data) { if (pos == string::npos) { return; } - string suffix = topic.substr(pos+1); + string direction = topic.substr(pos+1); bool isWrite = false; - if (suffix.empty()) { + if (direction.empty()) { return; } - string direction = suffix.substr(0, 3); isWrite = direction == "set"; if (!isWrite && direction != "get") { return; } - suffix = suffix.substr(3); // security level + logOtherDebug("mqtt", "received topic %s", topic.c_str(), data.c_str()); string remain = topic.substr(0, pos); size_t last = 0; @@ -457,12 +457,9 @@ void MqttHandler::notifyTopic(string topic, string data) { return; } logOtherInfo("mqtt", "received topic for %s %s", circuit.c_str(), name.c_str()); - if (suffix.length() > 0) { - circuit += "#"+suffix; - } - Message* message = m_messages->find(circuit, name, isWrite); + Message* message = m_messages->find(circuit, name, m_levels, isWrite); if (message == NULL) { - message = m_messages->find(circuit, name, isWrite, true); + message = m_messages->find(circuit, name, m_levels, isWrite, true); } if (message == NULL) { logOtherError("mqtt", "%s message %s %s not found", isWrite?"write":"read", circuit.c_str(), name.c_str()); diff --git a/src/ebusd/mqtthandler.h b/src/ebusd/mqtthandler.h index 4621f52d..c66514ce 100644 --- a/src/ebusd/mqtthandler.h +++ b/src/ebusd/mqtthandler.h @@ -45,11 +45,12 @@ const struct argp_child* mqtthandler_getargs(); /** * Registration function that is called once during initialization. + * @param userInfo the @a UserInfo instance. * @param busHandler the @a BusHandler instance. * @param messages the @a MessageMap instance. * @return the create @a DataHandler, or NULL on error. */ -DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages); +DataHandler* mqtthandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages); /** * The main class supporting MQTT data handling. @@ -58,10 +59,11 @@ class MqttHandler : public DataSink, public DataSource, public Thread { public: /** * Constructor. + * @param userInfo the @a UserInfo instance. * @param busHandler the @a BusHandler instance. * @param messages the @a MessageMap instance. */ - MqttHandler(BusHandler* busHandler, MessageMap* messages); + MqttHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages); /** * Destructor. @@ -120,7 +122,7 @@ class MqttHandler : public DataSink, public DataSource, public Thread { vector m_topicStrs; /** the MQTT topic column parts. */ - vector m_topicCols; + vector m_topicCols; /** the global topic prefix. */ string m_globalTopic;