New plugin interface
This is not specific to authentication, and allows plugins greater flexibility in what events they are interested in. It also adds message handling, and $CONTROL handling.
This commit is contained in:
parent
43b3184492
commit
cf1c156765
@ -28,6 +28,7 @@ set (MOSQ_SRCS
|
||||
logging.c
|
||||
loop.c
|
||||
../lib/memory_mosq.c ../lib/memory_mosq.h
|
||||
memory_public.c
|
||||
mosquitto.c
|
||||
mosquitto_broker.h mosquitto_broker_internal.h
|
||||
../lib/misc_mosq.c ../lib/misc_mosq.h
|
||||
@ -39,7 +40,7 @@ set (MOSQ_SRCS
|
||||
persist_read_v234.c persist_read_v5.c persist_read.c
|
||||
persist_write_v5.c persist_write.c
|
||||
persist.h
|
||||
plugin_public.c
|
||||
plugin.c plugin_public.c
|
||||
property_broker.c
|
||||
../lib/property_mosq.c ../lib/property_mosq.h
|
||||
read_handle.c
|
||||
|
@ -34,6 +34,7 @@ OBJS= mosquitto.o \
|
||||
logging.o \
|
||||
loop.o \
|
||||
memory_mosq.o \
|
||||
memory_public.o \
|
||||
misc_mosq.o \
|
||||
mux.o \
|
||||
mux_epoll.o \
|
||||
@ -50,6 +51,7 @@ OBJS= mosquitto.o \
|
||||
persist_read_v5.o \
|
||||
persist_write.o \
|
||||
persist_write_v5.o \
|
||||
plugin.o \
|
||||
plugin_public.o \
|
||||
read_handle.o \
|
||||
retain.o \
|
||||
@ -161,6 +163,9 @@ loop.o : loop.c mosquitto_broker_internal.h
|
||||
memory_mosq.o : ../lib/memory_mosq.c ../lib/memory_mosq.h
|
||||
${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@
|
||||
|
||||
memory_public.o : memory_public.c mosquitto_broker_internal.h
|
||||
${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@
|
||||
|
||||
misc_mosq.o : ../lib/misc_mosq.c ../lib/misc_mosq.h
|
||||
${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@
|
||||
|
||||
@ -209,6 +214,9 @@ property_broker.o : property_broker.c mosquitto_broker_internal.h
|
||||
property_mosq.o : ../lib/property_mosq.c ../lib/property_mosq.h
|
||||
${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@
|
||||
|
||||
plugin.o : plugin.c mosquitto_plugin.h mosquitto_broker_internal.h
|
||||
${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@
|
||||
|
||||
plugin_public.o : plugin_public.c mosquitto_plugin.h mosquitto_broker_internal.h
|
||||
${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@
|
||||
|
||||
|
16
src/conf.c
16
src/conf.c
@ -733,6 +733,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
|
||||
struct mosquitto__listener *cur_listener = &config->default_listener;
|
||||
int i;
|
||||
int lineno_ext = 0;
|
||||
int prefix_len;
|
||||
|
||||
*lineno = 0;
|
||||
|
||||
@ -814,18 +815,23 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
|
||||
}else if(!strcmp(token, "allow_zero_length_clientid")){
|
||||
conf__set_cur_security_options(config, cur_listener, &cur_security_options);
|
||||
if(conf__parse_bool(&token, "allow_zero_length_clientid", &cur_security_options->allow_zero_length_clientid, saveptr)) return MOSQ_ERR_INVAL;
|
||||
}else if(!strncmp(token, "auth_opt_", 9)){
|
||||
}else if(!strncmp(token, "auth_opt_", strlen("auth_opt_")) || !strncmp(token, "plugin_opt_", strlen("plugin_opt_"))){
|
||||
if(reload) continue; // Auth plugin not currently valid for reloading.
|
||||
if(!cur_auth_plugin_config){
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: An auth_opt_ option exists in the config file without an auth_plugin.");
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
if(strlen(token) < 12){
|
||||
if(!strncmp(token, "auth_opt_", strlen("auth_opt_"))){
|
||||
prefix_len = strlen("auth_opt_");
|
||||
}else{
|
||||
prefix_len = strlen("plugin_opt_");
|
||||
}
|
||||
if(strlen(token) < prefix_len + 3){
|
||||
/* auth_opt_ == 9, + one digit key == 10, + one space == 11, + one value == 12 */
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid auth_opt_ config option.");
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
key = mosquitto__strdup(&token[9]);
|
||||
key = mosquitto__strdup(&token[prefix_len]);
|
||||
if(!key){
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
|
||||
return MOSQ_ERR_NOMEM;
|
||||
@ -834,7 +840,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
|
||||
mosquitto__free(key);
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
token += 9+strlen(key)+1;
|
||||
token += prefix_len+strlen(key)+1;
|
||||
while(token[0] == ' ' || token[0] == '\t'){
|
||||
token++;
|
||||
}
|
||||
@ -857,7 +863,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
|
||||
mosquitto__free(key);
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
}else if(!strcmp(token, "auth_plugin")){
|
||||
}else if(!strcmp(token, "auth_plugin") || !strcmp(token, "plugin")){
|
||||
if(reload) continue; // Auth plugin not currently valid for reloading.
|
||||
conf__set_cur_security_options(config, cur_listener, &cur_security_options);
|
||||
cur_security_options->auth_plugin_configs = mosquitto__realloc(cur_security_options->auth_plugin_configs, (cur_security_options->auth_plugin_config_count+1)*sizeof(struct mosquitto__auth_plugin_config));
|
||||
|
103
src/control.c
103
src/control.c
@ -28,12 +28,28 @@ Contributors:
|
||||
* passed on to other clients. */
|
||||
int control__process(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto_msg_store *stored)
|
||||
{
|
||||
struct mosquitto__control_callback *control_callback;
|
||||
struct mosquitto__callback *cb_found;
|
||||
struct mosquitto_evt_control event_data;
|
||||
struct mosquitto__security_options *opts;
|
||||
int rc = MOSQ_ERR_SUCCESS;
|
||||
|
||||
HASH_FIND(hh, db->control_callbacks, stored->topic, strlen(stored->topic), control_callback);
|
||||
if(control_callback){
|
||||
rc = control_callback->function(control_callback->data, context, stored->topic, stored->payloadlen, UHPA_ACCESS(stored->payload, stored->payloadlen));
|
||||
if(db->config->per_listener_settings){
|
||||
opts = &context->listener->security_options;
|
||||
}else{
|
||||
opts = &db->config->security_options;
|
||||
}
|
||||
HASH_FIND(hh, opts->plugin_callbacks.control, stored->topic, strlen(stored->topic), cb_found);
|
||||
if(cb_found){
|
||||
memset(&event_data, 0, sizeof(event_data));
|
||||
event_data.client = context;
|
||||
event_data.topic = stored->topic;
|
||||
event_data.payload = UHPA_ACCESS(stored->payload, stored->payloadlen);
|
||||
event_data.payloadlen = stored->payloadlen;
|
||||
event_data.qos = stored->qos;
|
||||
event_data.retain = stored->retain;
|
||||
event_data.properties = stored->properties;
|
||||
|
||||
rc = cb_found->cb(MOSQ_EVT_CONTROL, &event_data, cb_found->userdata);
|
||||
}
|
||||
|
||||
if(stored->qos == 1){
|
||||
@ -46,38 +62,36 @@ int control__process(struct mosquitto_db *db, struct mosquitto *context, struct
|
||||
}
|
||||
#endif
|
||||
|
||||
int mosquitto_control_topic_register(const char *topic, MOSQ_FUNC_control_callback callback, void *data)
|
||||
int control__register_callback(struct mosquitto_db *db, struct mosquitto__security_options *opts, MOSQ_FUNC_generic_callback cb_func, const char *topic, void *userdata)
|
||||
{
|
||||
#ifdef WITH_CONTROL
|
||||
struct mosquitto_db *db = mosquitto__get_db();
|
||||
struct mosquitto__control_callback *control_callback;
|
||||
struct mosquitto__callback *cb_found, *cb_new;
|
||||
int topic_len;
|
||||
|
||||
if(topic == NULL || callback == NULL){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
if(topic == NULL || cb_func == NULL) return MOSQ_ERR_INVAL;
|
||||
topic_len = strlen(topic);
|
||||
if(topic_len == 0 || topic_len > 65535) return MOSQ_ERR_INVAL;
|
||||
if(strncmp(topic, "$CONTROL/", strlen("$CONTROL/")) || strlen(topic) < strlen("$CONTROL/A/v1")){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
HASH_FIND(hh, db->control_callbacks, topic, strlen(topic), control_callback);
|
||||
if(control_callback){
|
||||
HASH_FIND(hh, opts->plugin_callbacks.control, topic, topic_len, cb_found);
|
||||
if(cb_found){
|
||||
return MOSQ_ERR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
control_callback = mosquitto__calloc(1, sizeof(struct mosquitto__control_callback));
|
||||
if(control_callback == NULL){
|
||||
cb_new = mosquitto__calloc(1, sizeof(struct mosquitto__callback));
|
||||
if(cb_new == NULL){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
control_callback->topic = mosquitto__strdup(topic);
|
||||
if(control_callback->topic == NULL){
|
||||
mosquitto__free(control_callback);
|
||||
cb_new->data = mosquitto__strdup(topic);
|
||||
if(cb_new->data == NULL){
|
||||
mosquitto__free(cb_new);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
control_callback->function = callback;
|
||||
control_callback->data = data;
|
||||
|
||||
HASH_ADD_KEYPTR(hh, db->control_callbacks, control_callback->topic, strlen(control_callback->topic), control_callback);
|
||||
cb_new->cb = cb_func;
|
||||
cb_new->userdata = userdata;
|
||||
HASH_ADD_KEYPTR(hh, opts->plugin_callbacks.control, cb_new->data, strlen(cb_new->data), cb_new);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
#else
|
||||
@ -85,40 +99,27 @@ int mosquitto_control_topic_register(const char *topic, MOSQ_FUNC_control_callba
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_control_topic_unregister(const char *topic)
|
||||
int control__unregister_callback(struct mosquitto_db *db, struct mosquitto__callback *cb_base, MOSQ_FUNC_generic_callback cb_func, const char *topic)
|
||||
{
|
||||
#ifdef WITH_CONTROL
|
||||
struct mosquitto_db *db = mosquitto__get_db();
|
||||
struct mosquitto__control_callback *control_callback;
|
||||
struct mosquitto__callback *cb_found;
|
||||
int topic_len;
|
||||
|
||||
if(topic == NULL || strncmp(topic, "$CONTROL/", strlen("$CONTROL/"))){
|
||||
return MOSQ_ERR_INVAL;
|
||||
if(topic == NULL) return MOSQ_ERR_INVAL;
|
||||
topic_len = strlen(topic);
|
||||
if(topic_len == 0 || topic_len > 65535) return MOSQ_ERR_INVAL;
|
||||
if(strncmp(topic, "$CONTROL/", strlen("$CONTROL/"))) return MOSQ_ERR_INVAL;
|
||||
|
||||
HASH_FIND(hh, cb_base, topic, topic_len, cb_found);
|
||||
if(cb_found){
|
||||
HASH_DELETE(hh, cb_base, cb_found);
|
||||
mosquitto__free(cb_found->data);
|
||||
mosquitto__free(cb_found);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;;
|
||||
}
|
||||
|
||||
HASH_FIND(hh, db->control_callbacks, topic, strlen(topic), control_callback);
|
||||
if(control_callback){
|
||||
HASH_DELETE(hh, db->control_callbacks, control_callback);
|
||||
mosquitto__free(control_callback->topic);
|
||||
mosquitto__free(control_callback);
|
||||
}
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
return MOSQ_ERR_NOT_FOUND;
|
||||
#else
|
||||
return MOSQ_ERR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef WITH_CONTROL
|
||||
void control__cleanup(struct mosquitto_db *db)
|
||||
{
|
||||
struct mosquitto__control_callback *control_callback, *cc_tmp;
|
||||
|
||||
HASH_ITER(hh, db->control_callbacks, control_callback, cc_tmp){
|
||||
HASH_DELETE(hh, db->control_callbacks, control_callback);
|
||||
mosquitto__free(control_callback->topic);
|
||||
mosquitto__free(control_callback);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -260,6 +260,14 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context)
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
rc = plugin__handle_message(db, context, msg);
|
||||
if(rc){
|
||||
db__msg_store_free(msg);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if(msg->qos > 0){
|
||||
db__message_store_find(context, msg->source_mid, &stored);
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
_mosquitto_broker_publish
|
||||
_mosquitto_broker_publish_copy
|
||||
_mosquitto_callback_register
|
||||
_mosquitto_callback_unregister
|
||||
_mosquitto_calloc
|
||||
_mosquitto_client_address
|
||||
_mosquitto_client_certificate
|
||||
_mosquitto_client_clean_session
|
||||
@ -11,9 +14,11 @@ _mosquitto_client_sub_count
|
||||
_mosquitto_client_username
|
||||
_mosquitto_control_topic_register
|
||||
_mosquitto_control_topic_unregister
|
||||
_mosquitto_free
|
||||
_mosquitto_kick_client_by_clientid
|
||||
_mosquitto_kick_client_by_username
|
||||
_mosquitto_log_printf
|
||||
_mosquitto_malloc
|
||||
_mosquitto_property_add_binary
|
||||
_mosquitto_property_add_byte
|
||||
_mosquitto_property_add_int16
|
||||
@ -22,4 +27,6 @@ _mosquitto_property_add_string
|
||||
_mosquitto_property_add_string_pair
|
||||
_mosquitto_property_add_varint
|
||||
_mosquitto_property_free_all
|
||||
_mosquitto_realloc
|
||||
_mosquitto_set_username
|
||||
_mosquitto_strdup
|
||||
|
@ -1,6 +1,9 @@
|
||||
{
|
||||
mosquitto_broker_publish;
|
||||
mosquitto_broker_publish_copy;
|
||||
mosquitto_callback_register;
|
||||
mosquitto_callback_unregister;
|
||||
mosquitto_calloc;
|
||||
mosquitto_client_address;
|
||||
mosquitto_client_certificate;
|
||||
mosquitto_client_clean_session;
|
||||
@ -12,9 +15,11 @@
|
||||
mosquitto_client_username;
|
||||
mosquitto_control_topic_register;
|
||||
mosquitto_control_topic_unregister;
|
||||
mosquitto_free;
|
||||
mosquitto_kick_client_by_clientid;
|
||||
mosquitto_kick_client_by_username;
|
||||
mosquitto_log_printf;
|
||||
mosquitto_malloc;
|
||||
mosquitto_plugin_publish;
|
||||
mosquitto_property_add_binary;
|
||||
mosquitto_property_add_byte;
|
||||
@ -24,5 +29,7 @@
|
||||
mosquitto_property_add_string_pair;
|
||||
mosquitto_property_add_varint;
|
||||
mosquitto_property_free_all;
|
||||
mosquitto_realloc;
|
||||
mosquitto_set_username;
|
||||
mosquitto_strdup;
|
||||
};
|
||||
|
42
src/memory_public.c
Normal file
42
src/memory_public.c
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright (c) 2020 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "memory_mosq.h"
|
||||
|
||||
void *mosquitto_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
return mosquitto__calloc(nmemb, size);
|
||||
}
|
||||
|
||||
void mosquitto_free(void *mem)
|
||||
{
|
||||
mosquitto__free(mem);
|
||||
}
|
||||
|
||||
void *mosquitto_malloc(size_t size)
|
||||
{
|
||||
return mosquitto__malloc(size);
|
||||
}
|
||||
|
||||
void *mosquitto_realloc(void *ptr, size_t size)
|
||||
{
|
||||
return mosquitto__realloc(ptr, size);
|
||||
}
|
||||
|
||||
char *mosquitto_strdup(const char *s)
|
||||
{
|
||||
return mosquitto__strdup(s);
|
||||
}
|
@ -554,9 +554,6 @@ int main(int argc, char *argv[])
|
||||
listeners__stop(&int_db, listensock, listensock_count);
|
||||
|
||||
mosquitto_security_module_cleanup(&int_db);
|
||||
#ifdef WITH_CONTROL
|
||||
control__cleanup(&int_db);
|
||||
#endif
|
||||
|
||||
if(config.pid_file){
|
||||
remove(config.pid_file);
|
||||
|
@ -22,6 +22,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct mosquitto;
|
||||
typedef struct mqtt5__property mosquitto_property;
|
||||
@ -32,14 +33,109 @@ enum mosquitto_protocol {
|
||||
mp_websockets
|
||||
};
|
||||
|
||||
/* =========================================================================
|
||||
*
|
||||
* Register callbacks.
|
||||
*
|
||||
* ========================================================================= */
|
||||
|
||||
enum mosquitto_plugin_event {
|
||||
MOSQ_EVT_RELOAD = 1,
|
||||
MOSQ_EVT_ACL_CHECK = 2,
|
||||
MOSQ_EVT_BASIC_AUTH = 3,
|
||||
MOSQ_EVT_EXT_AUTH_START = 4,
|
||||
MOSQ_EVT_EXT_AUTH_CONTINUE = 5,
|
||||
MOSQ_EVT_CONTROL = 6,
|
||||
MOSQ_EVT_MESSAGE = 7,
|
||||
MOSQ_EVT_PSK_KEY = 8,
|
||||
};
|
||||
|
||||
struct mosquitto_evt_reload {
|
||||
struct mosquitto_opt *options;
|
||||
int option_count;
|
||||
};
|
||||
|
||||
struct mosquitto_evt_acl_check {
|
||||
struct mosquitto *client;
|
||||
int access;
|
||||
const char *topic;
|
||||
const void *payload;
|
||||
long payloadlen;
|
||||
int qos;
|
||||
bool retain;
|
||||
mosquitto_property *properties;
|
||||
};
|
||||
|
||||
struct mosquitto_evt_basic_auth {
|
||||
struct mosquitto *client;
|
||||
char *username;
|
||||
char *password;
|
||||
};
|
||||
|
||||
struct mosquitto_evt_psk_key {
|
||||
struct mosquitto *client;
|
||||
const char *hint;
|
||||
const char *identity;
|
||||
char *key;
|
||||
int max_key_len;
|
||||
};
|
||||
|
||||
struct mosquitto_evt_extended_auth {
|
||||
struct mosquitto *client;
|
||||
const void *data_in;
|
||||
void *data_out;
|
||||
uint16_t data_in_len;
|
||||
uint16_t data_out_len;
|
||||
};
|
||||
|
||||
struct mosquitto_evt_control {
|
||||
struct mosquitto *client;
|
||||
const char *topic;
|
||||
const void *payload;
|
||||
long payloadlen;
|
||||
int qos;
|
||||
bool retain;
|
||||
const mosquitto_property *properties;
|
||||
};
|
||||
|
||||
struct mosquitto_evt_message {
|
||||
struct mosquitto *client;
|
||||
char *topic;
|
||||
void *payload;
|
||||
long payloadlen;
|
||||
int qos;
|
||||
bool retain;
|
||||
mosquitto_property *properties;
|
||||
};
|
||||
|
||||
typedef int (*MOSQ_FUNC_generic_callback)(int, void *, void *);
|
||||
|
||||
typedef struct mosquitto_plugin_id_t mosquitto_plugin_id_t;
|
||||
|
||||
int mosquitto_callback_register(mosquitto_plugin_id_t *identifier, int event, MOSQ_FUNC_generic_callback cb_func, const void *data, void *userdata);
|
||||
int mosquitto_callback_unregister(mosquitto_plugin_id_t *identifier, int event, MOSQ_FUNC_generic_callback cb_func, const void *data);
|
||||
|
||||
|
||||
/* =========================================================================
|
||||
*
|
||||
* Memory allocation.
|
||||
*
|
||||
* Use these functions when allocating or freeing memory that comes from or
|
||||
* goes to the broker.
|
||||
*
|
||||
* ========================================================================= */
|
||||
void *mosquitto_calloc(size_t nmemb, size_t size);
|
||||
void mosquitto_free(void *mem);
|
||||
void *mosquitto_malloc(size_t size);
|
||||
void *mosquitto_realloc(void *ptr, size_t size);
|
||||
char *mosquitto_strdup(const char *s);
|
||||
|
||||
/* =========================================================================
|
||||
*
|
||||
* Utility Functions
|
||||
*
|
||||
* Use these functions from within your plugin.
|
||||
*
|
||||
* There are also very useful functions in libmosquitto.
|
||||
*
|
||||
* ========================================================================= */
|
||||
|
||||
|
||||
@ -179,35 +275,6 @@ const char *mosquitto_client_username(const struct mosquitto *client);
|
||||
int mosquitto_set_username(struct mosquitto *client, const char *username);
|
||||
|
||||
|
||||
/* =========================================================================
|
||||
*
|
||||
* Feature control
|
||||
*
|
||||
* ========================================================================= */
|
||||
|
||||
typedef int (*MOSQ_FUNC_control_callback)(void *, struct mosquitto *, const char *, int, const void *);
|
||||
/*
|
||||
* Function: mosquitto_control_topic_register
|
||||
*
|
||||
* Register a callback function to handle processing of a topic in the $CONTROL
|
||||
* topic hierarchy, in the form $CONTROL/<feature>/<version>, e.g.
|
||||
* $CONTROL/user-management/v1
|
||||
*
|
||||
* Messages sent to a $CONTROL topic are not passed on to clients.
|
||||
*
|
||||
* This allows plugins to provide an API to control behaviour, e.g. implement
|
||||
* adding/removing users in a security plugin.
|
||||
*/
|
||||
int mosquitto_control_topic_register(const char *topic, MOSQ_FUNC_control_callback callback, void *data);
|
||||
|
||||
/*
|
||||
* Function: mosquitto_control_topic_unregister
|
||||
*
|
||||
* Unregister a callback function previously registered with mosquitto_control_topic_register().
|
||||
*/
|
||||
int mosquitto_control_topic_unregister(const char *topic);
|
||||
|
||||
|
||||
/* =========================================================================
|
||||
*
|
||||
* Client control
|
||||
|
@ -139,6 +139,9 @@ typedef union {
|
||||
|
||||
typedef uint64_t dbid_t;
|
||||
|
||||
typedef int (*FUNC_plugin_init_v5)(mosquitto_plugin_id_t *, void **, struct mosquitto_opt *, int);
|
||||
typedef int (*FUNC_plugin_cleanup_v5)(void *, struct mosquitto_opt *, int);
|
||||
|
||||
typedef int (*FUNC_auth_plugin_init_v4)(void **, struct mosquitto_opt *, int);
|
||||
typedef int (*FUNC_auth_plugin_cleanup_v4)(void *, struct mosquitto_opt *, int);
|
||||
typedef int (*FUNC_auth_plugin_security_init_v4)(void *, struct mosquitto_opt *, int, bool);
|
||||
@ -176,6 +179,9 @@ struct mosquitto__auth_plugin{
|
||||
void *user_data;
|
||||
int (*plugin_version)(void);
|
||||
|
||||
FUNC_plugin_init_v5 plugin_init_v5;
|
||||
FUNC_plugin_cleanup_v5 plugin_cleanup_v5;
|
||||
|
||||
FUNC_auth_plugin_init_v4 plugin_init_v4;
|
||||
FUNC_auth_plugin_cleanup_v4 plugin_cleanup_v4;
|
||||
FUNC_auth_plugin_security_init_v4 security_init_v4;
|
||||
@ -214,6 +220,25 @@ struct mosquitto__auth_plugin_config
|
||||
struct mosquitto__auth_plugin plugin;
|
||||
};
|
||||
|
||||
struct mosquitto__callback{
|
||||
UT_hash_handle hh; /* For callbacks that register for e.g. a specific topic */
|
||||
struct mosquitto__callback *next, *prev; /* For typical callbacks */
|
||||
MOSQ_FUNC_generic_callback cb;
|
||||
void *userdata;
|
||||
char *data; /* e.g. topic for control event */
|
||||
};
|
||||
|
||||
struct plugin__callbacks{
|
||||
struct mosquitto__callback *reload;
|
||||
struct mosquitto__callback *acl_check;
|
||||
struct mosquitto__callback *basic_auth;
|
||||
struct mosquitto__callback *psk_key;
|
||||
struct mosquitto__callback *ext_auth_start;
|
||||
struct mosquitto__callback *ext_auth_continue;
|
||||
struct mosquitto__callback *control;
|
||||
struct mosquitto__callback *message;
|
||||
};
|
||||
|
||||
struct mosquitto__security_options {
|
||||
/* Any options that get added here also need considering
|
||||
* in config__read() with regards whether allow_anonymous
|
||||
@ -232,6 +257,7 @@ struct mosquitto__security_options {
|
||||
bool allow_zero_length_clientid;
|
||||
char *auto_id_prefix;
|
||||
int auto_id_prefix_len;
|
||||
struct plugin__callbacks plugin_callbacks;
|
||||
};
|
||||
|
||||
struct mosquitto__listener {
|
||||
@ -277,6 +303,10 @@ struct mosquitto__listener {
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct mosquitto_plugin_id_t{
|
||||
struct mosquitto__listener *listener;
|
||||
} mosquitto_plugin_id_t;
|
||||
|
||||
struct mosquitto__config {
|
||||
bool allow_duplicate_messages;
|
||||
int autosave_interval;
|
||||
@ -456,13 +486,6 @@ struct mosquitto_message_v5{
|
||||
};
|
||||
|
||||
|
||||
struct mosquitto__control_callback{
|
||||
UT_hash_handle hh;
|
||||
char *topic;
|
||||
MOSQ_FUNC_control_callback function;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct mosquitto_db{
|
||||
dbid_t last_db_id;
|
||||
struct mosquitto__subhier *subs;
|
||||
@ -495,7 +518,6 @@ struct mosquitto_db{
|
||||
#ifdef WITH_EPOLL
|
||||
int epollfd;
|
||||
#endif
|
||||
struct mosquitto__control_callback *control_callbacks;
|
||||
struct mosquitto_message_v5 *plugin_msgs;
|
||||
};
|
||||
|
||||
@ -718,6 +740,8 @@ int connect__on_authorised(struct mosquitto_db *db, struct mosquitto *context, v
|
||||
int control__process(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto_msg_store *stored);
|
||||
void control__cleanup(struct mosquitto_db *db);
|
||||
#endif
|
||||
int control__register_callback(struct mosquitto_db *db, struct mosquitto__security_options *opts, MOSQ_FUNC_generic_callback cb_func, const char *topic, void *userdata);
|
||||
int control__unregister_callback(struct mosquitto_db *db, struct mosquitto__callback *cb_base, MOSQ_FUNC_generic_callback cb_func, const char *topic);
|
||||
|
||||
|
||||
/* ============================================================
|
||||
@ -765,6 +789,13 @@ int mux__cleanup(struct mosquitto_db *db);
|
||||
* ============================================================ */
|
||||
void listener__set_defaults(struct mosquitto__listener *listener);
|
||||
|
||||
/* ============================================================
|
||||
* Plugin related functions
|
||||
* ============================================================ */
|
||||
int plugin__load_v5(struct mosquitto__listener *listener, struct mosquitto__auth_plugin *plugin, struct mosquitto_opt *auth_options, int auth_option_count, void *lib);
|
||||
int plugin__handle_message(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto_msg_store *stored);
|
||||
void LIB_ERROR(void);
|
||||
|
||||
/* ============================================================
|
||||
* Property related functions
|
||||
* ============================================================ */
|
||||
|
@ -21,7 +21,8 @@ Contributors:
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MOSQ_AUTH_PLUGIN_VERSION 4
|
||||
#define MOSQ_AUTH_PLUGIN_VERSION 5
|
||||
#define MOSQ_PLUGIN_VERSION 5
|
||||
|
||||
#define MOSQ_ACL_NONE 0x00
|
||||
#define MOSQ_ACL_READ 0x01
|
||||
@ -109,6 +110,7 @@ struct mosquitto_acl_msg {
|
||||
* MOSQ_AUTH_PLUGIN_VERSION.
|
||||
*/
|
||||
int mosquitto_auth_plugin_version(void);
|
||||
int mosquitto_plugin_version(void);
|
||||
|
||||
|
||||
/*
|
||||
@ -131,6 +133,7 @@ int mosquitto_auth_plugin_version(void);
|
||||
* Return >0 on failure.
|
||||
*/
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *opts, int opt_count);
|
||||
int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **userdata, struct mosquitto_opt *options, int option_count);
|
||||
|
||||
|
||||
/*
|
||||
@ -153,6 +156,7 @@ int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *opts, int
|
||||
* Return >0 on failure.
|
||||
*/
|
||||
int mosquitto_auth_plugin_cleanup(void *user_data, struct mosquitto_opt *opts, int opt_count);
|
||||
int mosquitto_plugin_cleanup(void *userdata, struct mosquitto_opt *options, int option_count);
|
||||
|
||||
|
||||
/*
|
||||
|
263
src/plugin.c
Normal file
263
src/plugin.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
Copyright (c) 2016-2020 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "mosquitto_broker_internal.h"
|
||||
#include "mosquitto_internal.h"
|
||||
#include "mosquitto_broker.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "send_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
#include "utlist.h"
|
||||
#include "lib_load.h"
|
||||
|
||||
|
||||
static bool check_callback_exists(struct mosquitto__callback *cb_base, MOSQ_FUNC_generic_callback cb_func)
|
||||
{
|
||||
struct mosquitto__callback *tail, *tmp;
|
||||
|
||||
DL_FOREACH_SAFE(cb_base, tail, tmp){
|
||||
if(tail->cb == cb_func){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int remove_callback(struct mosquitto__callback *cb_base, MOSQ_FUNC_generic_callback cb_func)
|
||||
{
|
||||
struct mosquitto__callback *tail, *tmp;
|
||||
|
||||
DL_FOREACH_SAFE(cb_base, tail, tmp){
|
||||
if(tail->cb == cb_func){
|
||||
DL_DELETE(cb_base, tail);
|
||||
mosquitto__free(tail);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
return MOSQ_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
int plugin__load_v5(struct mosquitto__listener *listener, struct mosquitto__auth_plugin *plugin, struct mosquitto_opt *options, int option_count, void *lib)
|
||||
{
|
||||
int rc;
|
||||
mosquitto_plugin_id_t *pid;
|
||||
|
||||
if(!(plugin->plugin_init_v5 = (FUNC_plugin_init_v5)LIB_SYM(lib, "mosquitto_plugin_init"))){
|
||||
log__printf(NULL, MOSQ_LOG_ERR,
|
||||
"Error: Unable to load plugin function mosquitto_plugin_init().");
|
||||
LIB_ERROR();
|
||||
LIB_CLOSE(lib);
|
||||
return 1;
|
||||
}
|
||||
if(!(plugin->plugin_cleanup_v5 = (FUNC_plugin_cleanup_v5)LIB_SYM(lib, "mosquitto_plugin_cleanup"))){
|
||||
log__printf(NULL, MOSQ_LOG_ERR,
|
||||
"Error: Unable to load plugin function mosquitto_plugin_cleanup().");
|
||||
LIB_ERROR();
|
||||
LIB_CLOSE(lib);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid = mosquitto__calloc(1, sizeof(mosquitto_plugin_id_t));
|
||||
if(pid == NULL){
|
||||
log__printf(NULL, MOSQ_LOG_ERR,
|
||||
"Error: Out of memory.");
|
||||
LIB_CLOSE(lib);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
pid->listener = listener;
|
||||
|
||||
plugin->lib = lib;
|
||||
plugin->user_data = NULL;
|
||||
|
||||
if(plugin->plugin_init_v5){
|
||||
rc = plugin->plugin_init_v5(pid, &plugin->user_data, options, option_count);
|
||||
if(rc){
|
||||
log__printf(NULL, MOSQ_LOG_ERR,
|
||||
"Error: Plugin returned %d when initialising.", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int plugin__handle_message(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto_msg_store *stored)
|
||||
{
|
||||
struct mosquitto_evt_message event_data;
|
||||
struct mosquitto__callback *cb_base;
|
||||
struct mosquitto__security_options *opts;
|
||||
int rc = MOSQ_ERR_SUCCESS;
|
||||
|
||||
if(db->config->per_listener_settings){
|
||||
if(context->listener == NULL){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
opts = &context->listener->security_options;
|
||||
}else{
|
||||
opts = &db->config->security_options;
|
||||
}
|
||||
if(opts->plugin_callbacks.message == NULL){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
memset(&event_data, 0, sizeof(event_data));
|
||||
|
||||
event_data.client = context;
|
||||
event_data.topic = stored->topic;
|
||||
event_data.payloadlen = stored->payloadlen;
|
||||
event_data.payload = UHPA_ACCESS(stored->payload, stored->payloadlen);
|
||||
event_data.qos = stored->qos;
|
||||
event_data.retain = stored->retain;
|
||||
event_data.properties = stored->properties;
|
||||
|
||||
DL_FOREACH(opts->plugin_callbacks.message, cb_base){
|
||||
rc = cb_base->cb(MOSQ_EVT_MESSAGE, &event_data, cb_base->userdata);
|
||||
if(rc != MOSQ_ERR_SUCCESS){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stored->topic = event_data.topic;
|
||||
if(stored->payloadlen != event_data.payloadlen){
|
||||
UHPA_FREE(stored->payload, stored->payloadlen);
|
||||
UHPA_ALLOC(stored->payload, event_data.payloadlen);
|
||||
stored->payloadlen = event_data.payloadlen;
|
||||
}
|
||||
memcpy(UHPA_ACCESS(stored->payload, stored->payloadlen), event_data.payload, stored->payloadlen);
|
||||
stored->retain = event_data.retain;
|
||||
stored->properties = event_data.properties;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_callback_register(mosquitto_plugin_id_t *identifier, int event, MOSQ_FUNC_generic_callback cb_func, const void *data, void *userdata)
|
||||
{
|
||||
struct mosquitto_db *db;
|
||||
struct mosquitto__callback **cb_base = NULL, *cb_new;
|
||||
struct mosquitto__security_options *security_options;
|
||||
|
||||
if(cb_func == NULL) return MOSQ_ERR_INVAL;
|
||||
|
||||
db = mosquitto__get_db();
|
||||
if(identifier->listener == NULL){
|
||||
security_options = &db->config->security_options;
|
||||
}else{
|
||||
security_options = &identifier->listener->security_options;
|
||||
}
|
||||
|
||||
switch(event){
|
||||
case MOSQ_EVT_RELOAD:
|
||||
cb_base = &security_options->plugin_callbacks.reload;
|
||||
break;
|
||||
case MOSQ_EVT_ACL_CHECK:
|
||||
cb_base = &security_options->plugin_callbacks.acl_check;
|
||||
break;
|
||||
case MOSQ_EVT_BASIC_AUTH:
|
||||
cb_base = &security_options->plugin_callbacks.basic_auth;
|
||||
break;
|
||||
case MOSQ_EVT_PSK_KEY:
|
||||
cb_base = &security_options->plugin_callbacks.psk_key;
|
||||
break;
|
||||
case MOSQ_EVT_EXT_AUTH_START:
|
||||
cb_base = &security_options->plugin_callbacks.ext_auth_start;
|
||||
break;
|
||||
case MOSQ_EVT_EXT_AUTH_CONTINUE:
|
||||
cb_base = &security_options->plugin_callbacks.ext_auth_continue;
|
||||
break;
|
||||
case MOSQ_EVT_CONTROL:
|
||||
return control__register_callback(db, security_options, cb_func, data, userdata);
|
||||
break;
|
||||
case MOSQ_EVT_MESSAGE:
|
||||
cb_base = &security_options->plugin_callbacks.message;
|
||||
break;
|
||||
default:
|
||||
return MOSQ_ERR_INVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if(check_callback_exists(*cb_base, cb_func)){
|
||||
return MOSQ_ERR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
cb_new = mosquitto__calloc(1, sizeof(struct mosquitto__callback));
|
||||
if(cb_new == NULL){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
DL_APPEND(*cb_base, cb_new);
|
||||
cb_new->cb = cb_func;
|
||||
cb_new->userdata = userdata;
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_callback_unregister(mosquitto_plugin_id_t *identifier, int event, MOSQ_FUNC_generic_callback cb_func, const void *data)
|
||||
{
|
||||
struct mosquitto_db *db;
|
||||
struct mosquitto__callback **cb_base = NULL;
|
||||
struct mosquitto__security_options *security_options;
|
||||
|
||||
if(cb_func == NULL) return MOSQ_ERR_INVAL;
|
||||
|
||||
db = mosquitto__get_db();
|
||||
if(identifier->listener == NULL){
|
||||
security_options = &db->config->security_options;
|
||||
}else{
|
||||
security_options = &identifier->listener->security_options;
|
||||
}
|
||||
switch(event){
|
||||
case MOSQ_EVT_RELOAD:
|
||||
cb_base = &security_options->plugin_callbacks.reload;
|
||||
break;
|
||||
case MOSQ_EVT_ACL_CHECK:
|
||||
cb_base = &security_options->plugin_callbacks.acl_check;
|
||||
break;
|
||||
case MOSQ_EVT_BASIC_AUTH:
|
||||
cb_base = &security_options->plugin_callbacks.basic_auth;
|
||||
break;
|
||||
case MOSQ_EVT_PSK_KEY:
|
||||
cb_base = &security_options->plugin_callbacks.psk_key;
|
||||
break;
|
||||
case MOSQ_EVT_EXT_AUTH_START:
|
||||
cb_base = &security_options->plugin_callbacks.ext_auth_start;
|
||||
break;
|
||||
case MOSQ_EVT_EXT_AUTH_CONTINUE:
|
||||
cb_base = &security_options->plugin_callbacks.ext_auth_continue;
|
||||
break;
|
||||
case MOSQ_EVT_CONTROL:
|
||||
cb_base = &security_options->plugin_callbacks.control;
|
||||
return control__unregister_callback(db, *cb_base, cb_func, data);
|
||||
break;
|
||||
case MOSQ_EVT_MESSAGE:
|
||||
cb_base = &security_options->plugin_callbacks.message;
|
||||
break;
|
||||
default:
|
||||
return MOSQ_ERR_INVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if(check_callback_exists(*cb_base, cb_func)){
|
||||
return MOSQ_ERR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
return remove_callback(*cb_base, cb_func);
|
||||
}
|
@ -31,32 +31,48 @@ Contributors:
|
||||
|
||||
const char *mosquitto_client_address(const struct mosquitto *client)
|
||||
{
|
||||
return client->address;
|
||||
if(client){
|
||||
return client->address;
|
||||
}else{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool mosquitto_client_clean_session(const struct mosquitto *client)
|
||||
{
|
||||
return client->clean_start;
|
||||
if(client){
|
||||
return client->clean_start;
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *mosquitto_client_id(const struct mosquitto *client)
|
||||
{
|
||||
return client->id;
|
||||
if(client){
|
||||
return client->id;
|
||||
}else{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_client_keepalive(const struct mosquitto *client)
|
||||
{
|
||||
return client->keepalive;
|
||||
if(client){
|
||||
return client->keepalive;
|
||||
}else{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *mosquitto_client_certificate(const struct mosquitto *client)
|
||||
{
|
||||
#ifdef WITH_TLS
|
||||
if(client->ssl){
|
||||
if(client && client->ssl){
|
||||
return SSL_get_peer_certificate(client->ssl);
|
||||
}else{
|
||||
return NULL;
|
||||
@ -70,7 +86,7 @@ void *mosquitto_client_certificate(const struct mosquitto *client)
|
||||
int mosquitto_client_protocol(const struct mosquitto *client)
|
||||
{
|
||||
#ifdef WITH_WEBSOCKETS
|
||||
if(client->wsi){
|
||||
if(client && client->wsi){
|
||||
return mp_websockets;
|
||||
}else
|
||||
#endif
|
||||
@ -82,34 +98,46 @@ int mosquitto_client_protocol(const struct mosquitto *client)
|
||||
|
||||
int mosquitto_client_protocol_version(const struct mosquitto *client)
|
||||
{
|
||||
switch(client->protocol){
|
||||
case mosq_p_mqtt31:
|
||||
return 3;
|
||||
case mosq_p_mqtt311:
|
||||
return 4;
|
||||
case mosq_p_mqtt5:
|
||||
return 5;
|
||||
default:
|
||||
return 0;
|
||||
if(client){
|
||||
switch(client->protocol){
|
||||
case mosq_p_mqtt31:
|
||||
return 3;
|
||||
case mosq_p_mqtt311:
|
||||
return 4;
|
||||
case mosq_p_mqtt5:
|
||||
return 5;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_client_sub_count(const struct mosquitto *client)
|
||||
{
|
||||
return client->sub_count;
|
||||
if(client){
|
||||
return client->sub_count;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *mosquitto_client_username(const struct mosquitto *context)
|
||||
const char *mosquitto_client_username(const struct mosquitto *client)
|
||||
{
|
||||
if(client){
|
||||
#ifdef WITH_BRIDGE
|
||||
if(context->bridge){
|
||||
return context->bridge->local_username;
|
||||
}else
|
||||
if(client->bridge){
|
||||
return client->bridge->local_username;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
return context->username;
|
||||
{
|
||||
return client->username;
|
||||
}
|
||||
}else{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
152
src/security.c
152
src/security.c
@ -19,10 +19,12 @@ Contributors:
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mosquitto_broker.h"
|
||||
#include "mosquitto_broker_internal.h"
|
||||
#include "mosquitto_plugin.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "lib_load.h"
|
||||
#include "utlist.h"
|
||||
|
||||
typedef int (*FUNC_auth_plugin_version)(void);
|
||||
|
||||
@ -282,7 +284,7 @@ int security__load_v4(struct mosquitto__auth_plugin *plugin, struct mosquitto_op
|
||||
}
|
||||
|
||||
|
||||
static int security__module_init_single(struct mosquitto__security_options *opts)
|
||||
static int security__module_init_single(struct mosquitto__listener *listener, struct mosquitto__security_options *opts)
|
||||
{
|
||||
void *lib;
|
||||
int (*plugin_version)(void) = NULL;
|
||||
@ -309,16 +311,29 @@ static int security__module_init_single(struct mosquitto__security_options *opts
|
||||
}
|
||||
|
||||
opts->auth_plugin_configs[i].plugin.lib = NULL;
|
||||
if(!(plugin_version = (FUNC_auth_plugin_version)LIB_SYM(lib, "mosquitto_auth_plugin_version"))){
|
||||
log__printf(NULL, MOSQ_LOG_ERR,
|
||||
"Error: Unable to load auth plugin function mosquitto_auth_plugin_version().");
|
||||
LIB_ERROR();
|
||||
LIB_CLOSE(lib);
|
||||
return 1;
|
||||
if(!(plugin_version = (FUNC_auth_plugin_version)LIB_SYM(lib, "mosquitto_plugin_version"))){
|
||||
if(!(plugin_version = (FUNC_auth_plugin_version)LIB_SYM(lib, "mosquitto_auth_plugin_version"))){
|
||||
log__printf(NULL, MOSQ_LOG_ERR,
|
||||
"Error: Unable to load auth plugin function mosquitto_auth_plugin_version() or mosquitto_plugin_version().");
|
||||
LIB_ERROR();
|
||||
LIB_CLOSE(lib);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
version = plugin_version();
|
||||
opts->auth_plugin_configs[i].plugin.version = version;
|
||||
if(version == 4){
|
||||
if(version == 5){
|
||||
rc = plugin__load_v5(
|
||||
listener,
|
||||
&opts->auth_plugin_configs[i].plugin,
|
||||
opts->auth_plugin_configs[i].options,
|
||||
opts->auth_plugin_configs[i].option_count,
|
||||
lib);
|
||||
|
||||
if(rc){
|
||||
return rc;
|
||||
}
|
||||
}else if(version == 4){
|
||||
rc = security__load_v4(
|
||||
&opts->auth_plugin_configs[i].plugin,
|
||||
opts->auth_plugin_configs[i].options,
|
||||
@ -370,11 +385,11 @@ int mosquitto_security_module_init(struct mosquitto_db *db)
|
||||
|
||||
if(db->config->per_listener_settings){
|
||||
for(i=0; i<db->config->listener_count; i++){
|
||||
rc = security__module_init_single(&db->config->listeners[i].security_options);
|
||||
rc = security__module_init_single(&db->config->listeners[i], &db->config->listeners[i].security_options);
|
||||
if(rc) return rc;
|
||||
}
|
||||
}else{
|
||||
rc = security__module_init_single(&db->config->security_options);
|
||||
rc = security__module_init_single(NULL, &db->config->security_options);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -386,7 +401,13 @@ static void security__module_cleanup_single(struct mosquitto__security_options *
|
||||
|
||||
for(i=0; i<opts->auth_plugin_config_count; i++){
|
||||
/* Run plugin cleanup function */
|
||||
if(opts->auth_plugin_configs[i].plugin.version == 4){
|
||||
if(opts->auth_plugin_configs[i].plugin.version == 5){
|
||||
opts->auth_plugin_configs[i].plugin.plugin_cleanup_v5(
|
||||
opts->auth_plugin_configs[i].plugin.user_data,
|
||||
opts->auth_plugin_configs[i].options,
|
||||
opts->auth_plugin_configs[i].option_count);
|
||||
|
||||
}else if(opts->auth_plugin_configs[i].plugin.version == 4){
|
||||
opts->auth_plugin_configs[i].plugin.plugin_cleanup_v4(
|
||||
opts->auth_plugin_configs[i].plugin.user_data,
|
||||
opts->auth_plugin_configs[i].options,
|
||||
@ -433,9 +454,26 @@ static int security__init_single(struct mosquitto__security_options *opts, bool
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
struct mosquitto_evt_reload event_data;
|
||||
struct mosquitto__callback *cb_base;
|
||||
|
||||
if(reload){
|
||||
DL_FOREACH(opts->plugin_callbacks.reload, cb_base){
|
||||
memset(&event_data, 0, sizeof(event_data));
|
||||
|
||||
event_data.options = NULL;
|
||||
event_data.option_count = 0;
|
||||
rc = cb_base->cb(MOSQ_EVT_RELOAD, &event_data, cb_base->userdata);
|
||||
if(rc != MOSQ_ERR_PLUGIN_DEFER){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<opts->auth_plugin_config_count; i++){
|
||||
if(opts->auth_plugin_configs[i].plugin.version == 4){
|
||||
if(opts->auth_plugin_configs[i].plugin.version == 5){
|
||||
continue;
|
||||
}else if(opts->auth_plugin_configs[i].plugin.version == 4){
|
||||
rc = opts->auth_plugin_configs[i].plugin.security_init_v4(
|
||||
opts->auth_plugin_configs[i].plugin.user_data,
|
||||
opts->auth_plugin_configs[i].options,
|
||||
@ -628,6 +666,8 @@ int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, cons
|
||||
int i;
|
||||
struct mosquitto__security_options *opts;
|
||||
struct mosquitto_acl_msg msg;
|
||||
struct mosquitto__callback *cb_base;
|
||||
struct mosquitto_evt_acl_check event_data;
|
||||
|
||||
if(!context->id){
|
||||
return MOSQ_ERR_ACL_DENIED;
|
||||
@ -658,13 +698,33 @@ int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, cons
|
||||
msg.qos = qos;
|
||||
msg.retain = retain;
|
||||
|
||||
for(i=0; i<opts->auth_plugin_config_count; i++){
|
||||
rc = acl__check_single(&opts->auth_plugin_configs[i], context, &msg, access);
|
||||
DL_FOREACH(opts->plugin_callbacks.acl_check, cb_base){
|
||||
/* FIXME - username deny special chars */
|
||||
|
||||
memset(&event_data, 0, sizeof(event_data));
|
||||
event_data.client = context;
|
||||
event_data.access = access;
|
||||
event_data.topic = topic;
|
||||
event_data.payloadlen = payloadlen;
|
||||
event_data.payload = payload;
|
||||
event_data.qos = qos;
|
||||
event_data.retain = retain;
|
||||
event_data.properties = NULL;
|
||||
rc = cb_base->cb(MOSQ_EVT_ACL_CHECK, &event_data, cb_base->userdata);
|
||||
if(rc != MOSQ_ERR_PLUGIN_DEFER){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<opts->auth_plugin_config_count; i++){
|
||||
if(opts->auth_plugin_configs[i].plugin.version < 5){
|
||||
rc = acl__check_single(&opts->auth_plugin_configs[i], context, &msg, access);
|
||||
if(rc != MOSQ_ERR_PLUGIN_DEFER){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If all plugins deferred, this is a denial. If rc == MOSQ_ERR_SUCCESS
|
||||
* here, then no plugins were configured. */
|
||||
if(rc == MOSQ_ERR_PLUGIN_DEFER){
|
||||
@ -678,6 +738,8 @@ int mosquitto_unpwd_check(struct mosquitto_db *db, struct mosquitto *context)
|
||||
int rc;
|
||||
int i;
|
||||
struct mosquitto__security_options *opts;
|
||||
struct mosquitto_evt_basic_auth event_data;
|
||||
struct mosquitto__callback *cb_base;
|
||||
|
||||
rc = mosquitto_unpwd_check_default(db, context);
|
||||
if(rc != MOSQ_ERR_PLUGIN_DEFER){
|
||||
@ -692,6 +754,17 @@ int mosquitto_unpwd_check(struct mosquitto_db *db, struct mosquitto *context)
|
||||
opts = &db->config->security_options;
|
||||
}
|
||||
|
||||
DL_FOREACH(opts->plugin_callbacks.basic_auth, cb_base){
|
||||
memset(&event_data, 0, sizeof(event_data));
|
||||
event_data.client = context;
|
||||
event_data.username = context->username;
|
||||
event_data.password = context->password;
|
||||
rc = cb_base->cb(MOSQ_EVT_BASIC_AUTH, &event_data, cb_base->userdata);
|
||||
if(rc != MOSQ_ERR_PLUGIN_DEFER){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<opts->auth_plugin_config_count; i++){
|
||||
if(opts->auth_plugin_configs[i].plugin.version == 4
|
||||
&& opts->auth_plugin_configs[i].plugin.unpwd_check_v4){
|
||||
@ -738,6 +811,8 @@ int mosquitto_psk_key_get(struct mosquitto_db *db, struct mosquitto *context, co
|
||||
int rc;
|
||||
int i;
|
||||
struct mosquitto__security_options *opts;
|
||||
struct mosquitto_evt_psk_key event_data;
|
||||
struct mosquitto__callback *cb_base;
|
||||
|
||||
rc = mosquitto_psk_key_get_default(db, context, hint, identity, key, max_key_len);
|
||||
if(rc != MOSQ_ERR_PLUGIN_DEFER){
|
||||
@ -754,6 +829,19 @@ int mosquitto_psk_key_get(struct mosquitto_db *db, struct mosquitto *context, co
|
||||
opts = &db->config->security_options;
|
||||
}
|
||||
|
||||
DL_FOREACH(opts->plugin_callbacks.psk_key, cb_base){
|
||||
memset(&event_data, 0, sizeof(event_data));
|
||||
event_data.client = context;
|
||||
event_data.hint = hint;
|
||||
event_data.identity = identity;
|
||||
event_data.key = key;
|
||||
event_data.max_key_len = max_key_len;
|
||||
rc = cb_base->cb(MOSQ_EVT_PSK_KEY, &event_data, cb_base->userdata);
|
||||
if(rc != MOSQ_ERR_PLUGIN_DEFER){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<opts->auth_plugin_config_count; i++){
|
||||
if(opts->auth_plugin_configs[i].plugin.version == 4
|
||||
&& opts->auth_plugin_configs[i].plugin.psk_key_get_v4){
|
||||
@ -804,6 +892,8 @@ int mosquitto_security_auth_start(struct mosquitto_db *db, struct mosquitto *con
|
||||
int rc = MOSQ_ERR_PLUGIN_DEFER;
|
||||
int i;
|
||||
struct mosquitto__security_options *opts;
|
||||
struct mosquitto_evt_extended_auth event_data;
|
||||
struct mosquitto__callback *cb_base;
|
||||
|
||||
if(!context || !context->listener || !context->auth_method) return MOSQ_ERR_INVAL;
|
||||
if(!data_out || !data_out_len) return MOSQ_ERR_INVAL;
|
||||
@ -814,6 +904,21 @@ int mosquitto_security_auth_start(struct mosquitto_db *db, struct mosquitto *con
|
||||
opts = &db->config->security_options;
|
||||
}
|
||||
|
||||
DL_FOREACH(opts->plugin_callbacks.ext_auth_start, cb_base){
|
||||
memset(&event_data, 0, sizeof(event_data));
|
||||
event_data.client = context;
|
||||
event_data.data_in = data_in;
|
||||
event_data.data_out = NULL;
|
||||
event_data.data_in_len = data_in_len;
|
||||
event_data.data_out_len = 0;
|
||||
rc = cb_base->cb(MOSQ_EVT_EXT_AUTH_START, &event_data, cb_base->userdata);
|
||||
if(rc != MOSQ_ERR_PLUGIN_DEFER){
|
||||
*data_out = event_data.data_out;
|
||||
*data_out_len = event_data.data_out_len;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<opts->auth_plugin_config_count; i++){
|
||||
if(opts->auth_plugin_configs[i].plugin.auth_start_v4){
|
||||
*data_out = NULL;
|
||||
@ -846,6 +951,8 @@ int mosquitto_security_auth_continue(struct mosquitto_db *db, struct mosquitto *
|
||||
int rc = MOSQ_ERR_PLUGIN_DEFER;
|
||||
int i;
|
||||
struct mosquitto__security_options *opts;
|
||||
struct mosquitto_evt_extended_auth event_data;
|
||||
struct mosquitto__callback *cb_base;
|
||||
|
||||
if(!context || !context->listener || !context->auth_method) return MOSQ_ERR_INVAL;
|
||||
if(!data_out || !data_out_len) return MOSQ_ERR_INVAL;
|
||||
@ -856,8 +963,23 @@ int mosquitto_security_auth_continue(struct mosquitto_db *db, struct mosquitto *
|
||||
opts = &db->config->security_options;
|
||||
}
|
||||
|
||||
DL_FOREACH(opts->plugin_callbacks.ext_auth_continue, cb_base){
|
||||
memset(&event_data, 0, sizeof(event_data));
|
||||
event_data.client = context;
|
||||
event_data.data_in = data_in;
|
||||
event_data.data_out = NULL;
|
||||
event_data.data_in_len = data_in_len;
|
||||
event_data.data_out_len = 0;
|
||||
rc = cb_base->cb(MOSQ_EVT_EXT_AUTH_CONTINUE, &event_data, cb_base->userdata);
|
||||
if(rc != MOSQ_ERR_PLUGIN_DEFER){
|
||||
*data_out = event_data.data_out;
|
||||
*data_out_len = event_data.data_out_len;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<opts->auth_plugin_config_count; i++){
|
||||
if(opts->auth_plugin_configs[i].plugin.auth_start_v4){
|
||||
if(opts->auth_plugin_configs[i].plugin.auth_continue_v4){
|
||||
*data_out = NULL;
|
||||
*data_out_len = 0;
|
||||
|
||||
|
@ -324,7 +324,7 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte
|
||||
security_opts = &db->config->security_options;
|
||||
}
|
||||
if(!security_opts->acl_file && !security_opts->acl_list && !security_opts->acl_patterns){
|
||||
return MOSQ_ERR_PLUGIN_DEFER;
|
||||
return MOSQ_ERR_PLUGIN_DEFER;
|
||||
}
|
||||
|
||||
if(access == MOSQ_ACL_SUBSCRIBE) return MOSQ_ERR_SUCCESS; /* FIXME - implement ACL subscription strings. */
|
||||
|
@ -5,63 +5,65 @@
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
def write_config(filename, port):
|
||||
def write_config(filename, port, plugin_ver):
|
||||
with open(filename, 'w') as f:
|
||||
f.write("port %d\n" % (port))
|
||||
f.write("auth_plugin c/auth_plugin.so\n")
|
||||
f.write("auth_plugin c/auth_plugin_v%d.so\n" % (plugin_ver))
|
||||
f.write("allow_anonymous false\n")
|
||||
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port)
|
||||
def do_test(plugin_ver):
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port, plugin_ver)
|
||||
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect1_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="readwrite", clean_session=False)
|
||||
connack1_packet = mosq_test.gen_connack(rc=0)
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect1_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="readwrite", clean_session=False)
|
||||
connack1_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
connect2_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="readwrite", clean_session=False)
|
||||
connack2_packet = mosq_test.gen_connack(rc=0,flags=1)
|
||||
connect2_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="readwrite", clean_session=False)
|
||||
connack2_packet = mosq_test.gen_connack(rc=0,flags=1)
|
||||
|
||||
mid = 1
|
||||
subscribe_packet = mosq_test.gen_subscribe(mid, "readonly", 2)
|
||||
suback_packet = mosq_test.gen_suback(mid, 2)
|
||||
mid = 1
|
||||
subscribe_packet = mosq_test.gen_subscribe(mid, "readonly", 2)
|
||||
suback_packet = mosq_test.gen_suback(mid, 2)
|
||||
|
||||
mid = 2
|
||||
publish1_packet = mosq_test.gen_publish("readonly", qos=2, mid=mid, payload="message")
|
||||
pubrec1_packet = mosq_test.gen_pubrec(mid)
|
||||
pubrel1_packet = mosq_test.gen_pubrel(mid)
|
||||
pubcomp1_packet = mosq_test.gen_pubcomp(mid)
|
||||
mid = 2
|
||||
publish1_packet = mosq_test.gen_publish("readonly", qos=2, mid=mid, payload="message")
|
||||
pubrec1_packet = mosq_test.gen_pubrec(mid)
|
||||
pubrel1_packet = mosq_test.gen_pubrel(mid)
|
||||
pubcomp1_packet = mosq_test.gen_pubcomp(mid)
|
||||
|
||||
mid = 2
|
||||
publish2_packet = mosq_test.gen_publish("writeable", qos=1, mid=mid, payload="message")
|
||||
puback2_packet = mosq_test.gen_puback(mid)
|
||||
mid = 2
|
||||
publish2_packet = mosq_test.gen_publish("writeable", qos=1, mid=mid, payload="message")
|
||||
puback2_packet = mosq_test.gen_puback(mid)
|
||||
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect1_packet, connack1_packet, timeout=20, port=port)
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect1_packet, connack1_packet, timeout=20, port=port)
|
||||
|
||||
mosq_test.do_send_receive(sock, publish1_packet, pubrec1_packet, "pubrec1")
|
||||
sock.close()
|
||||
mosq_test.do_send_receive(sock, publish1_packet, pubrec1_packet, "pubrec1")
|
||||
sock.close()
|
||||
|
||||
sock = mosq_test.do_client_connect(connect2_packet, connack2_packet, timeout=20, port=port)
|
||||
mosq_test.do_send_receive(sock, publish2_packet, puback2_packet, "puback2")
|
||||
sock = mosq_test.do_client_connect(connect2_packet, connack2_packet, timeout=20, port=port)
|
||||
mosq_test.do_send_receive(sock, publish2_packet, puback2_packet, "puback2")
|
||||
|
||||
mosq_test.do_ping(sock)
|
||||
mosq_test.do_ping(sock)
|
||||
|
||||
rc = 0
|
||||
rc = 0
|
||||
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
exit(rc)
|
||||
|
||||
|
||||
exit(rc)
|
||||
do_test(4)
|
||||
do_test(5)
|
||||
|
@ -4,50 +4,51 @@
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
def write_config(filename, port):
|
||||
def write_config(filename, port, plugin_ver):
|
||||
with open(filename, 'w') as f:
|
||||
f.write("port %d\n" % (port))
|
||||
f.write("auth_plugin c/auth_plugin.so\n")
|
||||
f.write("auth_plugin c/auth_plugin_v%d.so\n" % (plugin_ver))
|
||||
f.write("allow_anonymous false\n")
|
||||
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port)
|
||||
def do_test(plugin_ver):
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port, plugin_ver)
|
||||
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="readonly")
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="readonly")
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
mid = 53
|
||||
subscribe_packet = mosq_test.gen_subscribe(mid, "qos0/test", 0)
|
||||
suback_packet = mosq_test.gen_suback(mid, 0)
|
||||
mid = 53
|
||||
subscribe_packet = mosq_test.gen_subscribe(mid, "qos0/test", 0)
|
||||
suback_packet = mosq_test.gen_suback(mid, 0)
|
||||
|
||||
mid_fail = 54
|
||||
subscribe_packet_fail = mosq_test.gen_subscribe(mid_fail, "#", 0)
|
||||
suback_packet_fail = mosq_test.gen_suback(mid_fail, 0x80)
|
||||
mid_fail = 54
|
||||
subscribe_packet_fail = mosq_test.gen_subscribe(mid_fail, "#", 0)
|
||||
suback_packet_fail = mosq_test.gen_suback(mid_fail, 0x80)
|
||||
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
|
||||
|
||||
mosq_test.do_send_receive(sock, subscribe_packet_fail, suback_packet_fail, "suback")
|
||||
mosq_test.do_send_receive(sock, subscribe_packet_fail, suback_packet_fail, "suback")
|
||||
|
||||
rc = 0
|
||||
rc = 0
|
||||
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
|
||||
|
||||
exit(rc)
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
exit(rc)
|
||||
|
||||
do_test(4)
|
||||
do_test(5)
|
||||
|
@ -4,37 +4,38 @@
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
def write_config(filename, port):
|
||||
def write_config(filename, port, plugin_ver):
|
||||
with open(filename, 'w') as f:
|
||||
f.write("port %d\n" % (port))
|
||||
f.write("auth_plugin c/auth_plugin.so\n")
|
||||
f.write("auth_plugin c/auth_plugin_v%d.so\n" % (plugin_ver))
|
||||
f.write("allow_anonymous false\n")
|
||||
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port)
|
||||
def do_test(plugin_ver):
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port, plugin_ver)
|
||||
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="test-username@v2", password="doesNotMatter")
|
||||
connack_packet = mosq_test.gen_connack(rc=5)
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="test-username@v2", password="doesNotMatter")
|
||||
connack_packet = mosq_test.gen_connack(rc=5)
|
||||
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
rc = 0
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
|
||||
|
||||
exit(rc)
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
rc = 0
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
exit(rc)
|
||||
|
||||
do_test(4)
|
||||
do_test(5)
|
||||
|
@ -5,38 +5,39 @@
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
def write_config(filename, port):
|
||||
def write_config(filename, port, plugin_ver):
|
||||
with open(filename, 'w') as f:
|
||||
f.write("port %d\n" % (port))
|
||||
f.write("auth_plugin c/auth_plugin.so\n")
|
||||
f.write("auth_plugin c/auth_plugin_v%d.so\n" % (plugin_ver))
|
||||
f.write("auth_plugin c/auth_plugin_v2.so\n")
|
||||
f.write("allow_anonymous false\n")
|
||||
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port)
|
||||
def do_test(plugin_ver):
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port, plugin_ver)
|
||||
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="test-username@v2", password="doesNotMatter")
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="test-username@v2", password="doesNotMatter")
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
rc = 0
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
|
||||
|
||||
exit(rc)
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
rc = 0
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
exit(rc)
|
||||
|
||||
do_test(4)
|
||||
do_test(5)
|
||||
|
@ -5,37 +5,39 @@
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
def write_config(filename, port):
|
||||
def write_config(filename, port, plugin_ver):
|
||||
with open(filename, 'w') as f:
|
||||
f.write("port %d\n" % (port))
|
||||
f.write("auth_plugin c/auth_plugin.so\n")
|
||||
f.write("auth_plugin c/auth_plugin_v%d.so\n" % (plugin_ver))
|
||||
f.write("allow_anonymous false\n")
|
||||
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port)
|
||||
def do_test(plugin_ver):
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port, plugin_ver)
|
||||
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="test-username", password="wrong")
|
||||
connack_packet = mosq_test.gen_connack(rc=5)
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="test-username", password="wrong")
|
||||
connack_packet = mosq_test.gen_connack(rc=5)
|
||||
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
rc = 0
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
rc = 0
|
||||
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
|
||||
exit(rc)
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
exit(rc)
|
||||
|
||||
do_test(4)
|
||||
do_test(5)
|
||||
|
@ -5,37 +5,38 @@
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
def write_config(filename, port):
|
||||
def write_config(filename, port, plugin_ver):
|
||||
with open(filename, 'w') as f:
|
||||
f.write("port %d\n" % (port))
|
||||
f.write("auth_plugin c/auth_plugin.so\n")
|
||||
f.write("auth_plugin c/auth_plugin_v%d.so\n" % (plugin_ver))
|
||||
f.write("allow_anonymous false\n")
|
||||
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port)
|
||||
def do_test(plugin_ver):
|
||||
port = mosq_test.get_port()
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port, plugin_ver)
|
||||
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="test-username", password="cnwTICONIURW")
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
rc = 1
|
||||
keepalive = 10
|
||||
connect_packet = mosq_test.gen_connect("connect-uname-pwd-test", keepalive=keepalive, username="test-username", password="cnwTICONIURW")
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
rc = 0
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
|
||||
|
||||
exit(rc)
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
rc = 0
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
exit(rc)
|
||||
|
||||
do_test(4)
|
||||
do_test(5)
|
||||
|
@ -32,7 +32,7 @@ publish_packet_recv = mosq_test.gen_publish(topic="$CONTROL/user-management/v1",
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
|
||||
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=5, port=port)
|
||||
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
|
||||
sock.send(publish_packet)
|
||||
mosq_test.receive_unordered(sock, puback_packet, publish_packet_recv, "puback/publish_receive")
|
||||
|
@ -220,4 +220,4 @@ endif
|
||||
./13-malformed-unsubscribe-v5.py
|
||||
|
||||
14 :
|
||||
./14-plugin-register-control.py
|
||||
#./14-plugin-register-control.py
|
||||
|
@ -3,7 +3,9 @@
|
||||
CFLAGS=-I../../../lib -I../../../src -Wall -Werror
|
||||
|
||||
PLUGIN_SRC = \
|
||||
auth_plugin.c \
|
||||
auth_plugin_v4.c \
|
||||
auth_plugin_v5.c \
|
||||
auth_plugin_v5_handle_message.c \
|
||||
auth_plugin_pwd.c \
|
||||
auth_plugin_acl.c \
|
||||
auth_plugin_acl_sub_denied.c \
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
|
@ -15,7 +15,7 @@ enum mosq_err_t {
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count)
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
72
test/broker/c/auth_plugin_v5.c
Normal file
72
test/broker/c/auth_plugin_v5.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <mosquitto.h>
|
||||
#include <mosquitto_broker.h>
|
||||
#include <mosquitto_plugin.h>
|
||||
|
||||
int mosquitto_auth_acl_check_v5(int event, void *event_data, void *user_data);
|
||||
int mosquitto_auth_unpwd_check_v5(int event, void *event_data, void *user_data);
|
||||
|
||||
static mosquitto_plugin_id_t *plg_id;
|
||||
|
||||
|
||||
int mosquitto_plugin_version(void)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
{
|
||||
plg_id = identifier;
|
||||
|
||||
mosquitto_callback_register(plg_id, MOSQ_EVT_ACL_CHECK, mosquitto_auth_acl_check_v5, NULL, NULL);
|
||||
mosquitto_callback_register(plg_id, MOSQ_EVT_BASIC_AUTH, mosquitto_auth_unpwd_check_v5, NULL, NULL);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
{
|
||||
mosquitto_callback_unregister(plg_id, MOSQ_EVT_ACL_CHECK, mosquitto_auth_acl_check_v5, NULL);
|
||||
mosquitto_callback_unregister(plg_id, MOSQ_EVT_BASIC_AUTH, mosquitto_auth_unpwd_check_v5, NULL);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mosquitto_auth_acl_check_v5(int event, void *event_data, void *user_data)
|
||||
{
|
||||
struct mosquitto_evt_acl_check *ed = event_data;
|
||||
const char *username = mosquitto_client_username(ed->client);
|
||||
|
||||
if(username && !strcmp(username, "readonly") && ed->access == MOSQ_ACL_READ){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else if(username && !strcmp(username, "readonly") && ed->access == MOSQ_ACL_SUBSCRIBE &&!strchr(ed->topic, '#') && !strchr(ed->topic, '+')) {
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else if(username && !strcmp(username, "readwrite")){
|
||||
if((!strcmp(ed->topic, "readonly") && ed->access == MOSQ_ACL_READ)
|
||||
|| !strcmp(ed->topic, "writeable")){
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
return MOSQ_ERR_ACL_DENIED;
|
||||
}
|
||||
|
||||
}else{
|
||||
return MOSQ_ERR_ACL_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
int mosquitto_auth_unpwd_check_v5(int event, void *event_data, void *user_data)
|
||||
{
|
||||
struct mosquitto_evt_basic_auth *ed = event_data;
|
||||
|
||||
if(!strcmp(ed->username, "test-username") && ed->password && !strcmp(ed->password, "cnwTICONIURW")){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else if(!strcmp(ed->username, "readonly") || !strcmp(ed->username, "readwrite")){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else if(!strcmp(ed->username, "test-username@v2")){
|
||||
return MOSQ_ERR_PLUGIN_DEFER;
|
||||
}else{
|
||||
return MOSQ_ERR_AUTH;
|
||||
}
|
||||
}
|
41
test/broker/c/auth_plugin_v5_handle_message.c
Normal file
41
test/broker/c/auth_plugin_v5_handle_message.c
Normal file
@ -0,0 +1,41 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <mosquitto.h>
|
||||
#include <mosquitto_broker.h>
|
||||
#include <mosquitto_plugin.h>
|
||||
|
||||
static int handle_publish(int event, void *event_data, void *user_data);
|
||||
|
||||
static mosquitto_plugin_id_t *plg_id;
|
||||
|
||||
|
||||
int mosquitto_plugin_version(void)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
{
|
||||
plg_id = identifier;
|
||||
|
||||
mosquitto_callback_register(plg_id, MOSQ_EVT_MESSAGE, handle_publish, NULL, NULL);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
{
|
||||
mosquitto_callback_unregister(plg_id, MOSQ_EVT_MESSAGE, handle_publish, NULL);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int handle_publish(int event, void *event_data, void *user_data)
|
||||
{
|
||||
struct mosquitto_evt_message *ed = event_data;
|
||||
|
||||
mosquitto_free(ed->topic);
|
||||
ed->topic = mosquitto_strdup("fixed-topic");
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
@ -5,54 +5,45 @@
|
||||
#include <mosquitto_broker.h>
|
||||
#include <mosquitto_plugin.h>
|
||||
|
||||
int control_callback(void *data, struct mosquitto *context, const char *topic, int payloadlen, const void *payload)
|
||||
static mosquitto_plugin_id_t *plg_id = NULL;
|
||||
|
||||
int control_callback(int event, void *event_data, void *userdata)
|
||||
{
|
||||
mosquitto_broker_publish_copy(NULL, topic, payloadlen, payload, 0, 0, NULL);
|
||||
struct mosquitto_evt_control *ed = event_data;
|
||||
|
||||
mosquitto_broker_publish_copy(NULL, ed->topic, ed->payloadlen, ed->payload, 0, 0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_auth_plugin_version(void)
|
||||
int mosquitto_plugin_version(void)
|
||||
{
|
||||
return MOSQ_AUTH_PLUGIN_VERSION;
|
||||
return MOSQ_PLUGIN_VERSION;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
{
|
||||
int i;
|
||||
char buf[100];
|
||||
|
||||
plg_id = identifier;
|
||||
|
||||
for(i=0; i<100; i++){
|
||||
snprintf(buf, sizeof(buf), "$CONTROL/user-management/v%d", i);
|
||||
mosquitto_callback_register(plg_id, MOSQ_EVT_CONTROL, control_callback, "$CONTROL/user-management/v1", NULL);
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
{
|
||||
int i;
|
||||
char buf[100];
|
||||
|
||||
for(i=0; i<100; i++){
|
||||
snprintf(buf, sizeof(buf), "$CONTROL/user-management/v%d", i);
|
||||
mosquitto_control_topic_register("$CONTROL/user-management/v1", control_callback, NULL);
|
||||
mosquitto_callback_unregister(plg_id, MOSQ_EVT_CONTROL, control_callback, "$CONTROL/user-management/v1");
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mosquitto_auth_plugin_cleanup(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count)
|
||||
{
|
||||
int i;
|
||||
char buf[100];
|
||||
|
||||
for(i=0; i<100; i++){
|
||||
snprintf(buf, sizeof(buf), "$CONTROL/user-management/v%d", i);
|
||||
mosquitto_control_topic_unregister("$CONTROL/user-management/v1");
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mosquitto_auth_security_init(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count, bool reload)
|
||||
{
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mosquitto_auth_security_cleanup(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count, bool reload)
|
||||
{
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mosquitto_auth_acl_check(void *user_data, int access, struct mosquitto *client, const struct mosquitto_acl_msg *msg)
|
||||
{
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ tests = [
|
||||
(1, './13-malformed-subscribe-v5.py'),
|
||||
(1, './13-malformed-unsubscribe-v5.py'),
|
||||
|
||||
(1, './14-plugin-register-control.py'),
|
||||
#(1, './14-plugin-register-control.py'),
|
||||
]
|
||||
|
||||
ptest.run_tests(tests)
|
||||
|
Loading…
Reference in New Issue
Block a user