Add the `global_plugin` option.

This gives global plugin loaded regardless of `per_listener_settings`.
pull/2386/head
Roger A. Light 4 years ago
parent 8cd2411ab6
commit 40b402e64a

@ -41,6 +41,8 @@ Broker:
across the broker, so only a single plugin can register for a given $CONTROL
topic.
- Password salts are now 64 bytes long.
- Add the `global_plugin` option, which gives global plugin loaded regardless
of `per_listener_settings`.
Client library:
- Add MOSQ_OPT_DISABLE_SOCKETPAIR to allow the disabling of the socketpair

@ -205,9 +205,9 @@
<varlistentry>
<term><option>allow_duplicate_messages</option> [ true | false ]</term>
<listitem>
<para>This option is deprecated and will be removed in a
future version. The behaviour will default to true.
</para>
<para>This option is deprecated and will be removed in a
future version. The behaviour will default to true.
</para>
<para>If a client is subscribed to multiple subscriptions
that overlap, e.g. foo/# and foo/+/baz , then MQTT
expects that when the broker receives a message on a
@ -252,35 +252,6 @@
<para>Reloaded on reload signal.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>auth_opt_*</option> <replaceable>value</replaceable></term>
<listitem>
<para>Options to be passed to the auth plugin. See the
specific plugin instructions.</para>
<para>Applies to the current authentication plugin being configured.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>auth_plugin</option> <replaceable>file path</replaceable></term>
<listitem>
<para>Specify an external module to use for authentication
and access control. This allows custom
username/password and access control functions to be
created.</para>
<para>Can be specified multiple times to load multiple
plugins. The plugins will be processed in the order
that they are specified.</para>
<para>If <option>password_file</option>, or
<option>acl_file</option> are used in the config file
alongsize <option>auth_plugin</option>, the plugin
checks will run after the built in checks.</para>
<para>Not currently reloaded on reload signal.</para>
<para>See also
<ulink url="https://mosquitto.org/documentation/dynamic-security/"/>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>auth_plugin_deny_special_chars</option> [ true | false ]</term>
<listitem>
@ -382,8 +353,8 @@
<varlistentry>
<term><option>clientid_prefixes</option> <replaceable>prefix</replaceable></term>
<listitem>
<para>This option is deprecated and will be removed in a
future version.</para>
<para>This option is deprecated and will be removed in a
future version.</para>
<para>If defined, only clients that have a clientid with a
prefix that matches clientid_prefixes will be allowed
to connect to the broker. For example, setting
@ -411,6 +382,30 @@
<para>Reloaded on reload signal.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>global_plugin</option> <replaceable>file path</replaceable></term>
<listitem>
<para>
Load an external module to extend broker features. This loads plugins
for use across all listeners, regardless of the value of the
<option>per_listener_settings</option> option. This option functions
the same as the <option>plugin</option> option in all other ways.
</para>
<para>
If you set <option>per_listener_settings true</option>, then define both a
<option>global_plugin</option> and a <option>plugin</option> (which will be
attached to a specific listener), then the global plugin will always be
processed first.
</para>
<para>
If you set <option>per_listener_settings false</option>, then
<option>global_plugin</option> behaves identically to
<option>plugin</option>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>include_dir</option> <replaceable>dir</replaceable></term>
<listitem>
@ -781,7 +776,7 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S
<option>acl_file</option>, <option>psk_file</option>,
<option>allow_anonymous</option>,
<option>allow_zero_length_clientid</option>,
<option>auth_plugin</option>,
<option>plugin</option>,
<option>auth_opt_*</option>,
<option>auto_id_prefix</option>.</para>
<para>Note that if set to true, then a durable client (i.e.
@ -886,6 +881,43 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S
<para>Not reloaded on reload signal.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>plugin_opt_*</option> <replaceable>value</replaceable></term>
<term><option>auth_opt_*</option> <replaceable>value</replaceable></term>
<listitem>
<para>Options to be passed to a plugin. See the
specific plugin instructions.</para>
<para>Applies to the current plugin/global_plugin being configured.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>plugin</option> <replaceable>file path</replaceable></term>
<term><option>auth_plugin</option> <replaceable>file path</replaceable></term>
<listitem>
<para>Specify an external module to use for authentication,
access control, and other features. This allows custom
username/password and access control functions to be
created and other behaviour to be modified.</para>
<para>Can be specified multiple times to load multiple
plugins. The plugins will be processed in the order
that they are specified.</para>
<para>If <option>password_file</option>, or
<option>acl_file</option> are used in the config file
alongsize <option>plugin</option>, the plugin
checks will run after the built in checks.</para>
<para>Not currently reloaded on reload signal.</para>
<para>
If <option>per_listener_settings</option> is set to
<replaceable>true</replaceable>, this plugin will be
loaded for the current listener only.
</para>
<para>See also
<ulink url="https://mosquitto.org/documentation/dynamic-security/"/>
and the <option>global_plugin</option> option.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>psk_file</option> <replaceable>file path</replaceable></term>
<listitem>
@ -1022,9 +1054,9 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S
<varlistentry>
<term><option>bind_address</option> <replaceable>address</replaceable></term>
<listitem>
<para>This option is deprecated and will be removed in a
<para>This option is deprecated and will be removed in a
future version. Use the <option>listener</option> instead.
</para>
</para>
<para>Listen for incoming network connections on the
specified IP address/hostname only. This is useful
to restrict access to certain network interfaces.
@ -1185,9 +1217,9 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S
<varlistentry>
<term><option>port</option> <replaceable>port number</replaceable></term>
<listitem>
<para>This option is deprecated and will be removed in a
<para>This option is deprecated and will be removed in a
future version. Use the <option>listener</option> instead.
</para>
</para>
<para>Set the network port for the default listener to
listen on. Defaults to 1883.</para>
<para>Not reloaded on reload signal.</para>
@ -1331,21 +1363,21 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S
<varlistentry>
<term><option>ciphers</option> <replaceable>cipher:list</replaceable></term>
<listitem>
<para>
The list of allowed ciphers for this listener, for
TLS v1.2 and earlier only, each separated with
a colon. Available ciphers can be obtained using
the "openssl ciphers" command.
</para>
<para>
The list of allowed ciphers for this listener, for
TLS v1.2 and earlier only, each separated with
a colon. Available ciphers can be obtained using
the "openssl ciphers" command.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>ciphers_tls1.3</option> <replaceable>cipher:list</replaceable></term>
<listitem>
<para>
The list of allowed ciphersuites for this listener,
for TLS v1.3, each separated with a colon.
</para>
<para>
The list of allowed ciphersuites for this listener,
for TLS v1.3, each separated with a colon.
</para>
</listitem>
</varlistentry>
<varlistentry>
@ -1649,15 +1681,15 @@ openssl dhparam -out dhparam.pem 2048</programlisting>
<varlistentry>
<term><option>bridge_tcp_keepalive</option> <replaceable>idle</replaceable> <replaceable>interval</replaceable> <replaceable>counter</replaceable></term>
<listitem>
<para>
Set TCP keepalive parameters for this bridge connection.
Use this option to allow you to set a long MQTT
keepalive value, whilst still being able to detect the
connection dropping in a reasonable time.
<para>
Set TCP keepalive parameters for this bridge connection.
Use this option to allow you to set a long MQTT
keepalive value, whilst still being able to detect the
connection dropping in a reasonable time.
</para>
<para>
This may be useful when bridging to services that bill
for PINGREQ messages.
This may be useful when bridging to services that bill
for PINGREQ messages.
</para>
<para>Disabled by default.</para>
</listitem>

@ -19,7 +19,7 @@
# options are controlled on a per listener basis. The following options are
# affected:
#
# password_file acl_file psk_file auth_plugin auth_opt_* allow_anonymous
# password_file acl_file psk_file plugin plugin_opt_* allow_anonymous
# auto_id_prefix allow_zero_length_clientid
#
# Note that if set to true, then a durable client (i.e. with clean session set
@ -529,8 +529,8 @@
# offers very little in the way of security.
#
# See the TLS client require_certificate and use_identity_as_username options
# for alternative authentication options. If an auth_plugin is used as well as
# password_file, the auth_plugin check will be made first.
# for alternative authentication options. If a plugin is used as well as
# password_file, the plugin check will be made after the password_file check.
#password_file
# Access may also be controlled using a pre-shared-key file. This requires
@ -538,7 +538,7 @@
# lines in the format:
# identity:key
# The key should be in hexadecimal format without a leading "0x".
# If an auth_plugin is used as well, the auth_plugin check will be made first.
# If an plugin is used as well, the plugin check will be made second.
#psk_file
# Control access to topics on the broker using an access control list
@ -592,8 +592,8 @@
#
# pattern write sensor/%u/data
#
# If an auth_plugin is used as well as acl_file, the auth_plugin check will be
# made first.
# If an plugin is used as well as acl_file, the plugin check will be
# made after the acl_file check.
#acl_file
# -----------------------------------------------------------------
@ -601,25 +601,39 @@
# -----------------------------------------------------------------
# External authentication and access control can be supported with the
# auth_plugin option. This is a path to a loadable plugin. See also the
# auth_opt_* options described below.
# plugin option. This is a path to a loadable plugin. See also the
# plugin_opt_* options described below.
#
# The auth_plugin option can be specified multiple times to load multiple
# The plugin option can be specified multiple times to load multiple
# plugins. The plugins will be processed in the order that they are specified
# here. If the auth_plugin option is specified alongside either of
# password_file or acl_file then the plugin checks will be made first.
# here. If the plugin option is specified alongside either of
# password_file or acl_file then the plugin checks will be made after the built
# in checks.
#
#auth_plugin
#plugin <path to plugin>
# If the auth_plugin option above is used, define options to pass to the
# If the plugin option above is used, define options to pass to the
# plugin here as described by the plugin instructions. All options named
# using the format auth_opt_* will be passed to the plugin, for example:
# using the format plugin_opt_* will be passed to the plugin, for example:
#
# auth_opt_db_host
# auth_opt_db_port
# auth_opt_db_username
# auth_opt_db_password
# plugin_opt_db_host
# plugin_opt_db_port
# plugin_opt_db_username
# plugin_opt_db_password
# The `plugin` option is affected by the `per_listener_settings` option. If you
# want to set `per_listener_settings true` but still want to use a plugin work
# across all listeners, then use the `global_plugin` option. This option
# functions the same as the `plugin` option in all other ways.
#
# If you set `per_listener_settings true`, then define both a `global_plugin`
# and a `plugin` (which will be attached to a specific listener), then the
# global plugin will always be processed first.
#
# If you set `per_listener_settings false`, then `global_plugin` behaves
# identically to `plugin`.
#
#global_plugin <path to plugin>
# =================================================================
# Bridges

@ -928,9 +928,14 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload,
mosquitto__free(key);
return MOSQ_ERR_INVAL;
}
}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);
}else if(!strcmp(token, "auth_plugin") || !strcmp(token, "plugin") || !strcmp(token, "global_plugin")){
if(reload) continue; /* plugin not currently valid for reloading. */
if(!strcmp(token, "global_plugin")){
cur_security_options = &db.config->security_options;
}else{
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, (size_t)(cur_security_options->auth_plugin_config_count+1)*sizeof(struct mosquitto__auth_plugin_config));
if(!cur_security_options->auth_plugin_configs){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");

@ -104,22 +104,12 @@ int plugin__load_v5(struct mosquitto__listener *listener, struct mosquitto__auth
}
void plugin__handle_connect(struct mosquitto *context)
static void plugin__handle_connect_single(struct mosquitto__security_options *opts, struct mosquitto *context)
{
struct mosquitto_evt_connect event_data;
struct mosquitto__callback *cb_base;
struct mosquitto__security_options *opts;
if(db.config->per_listener_settings){
if(context->listener == NULL){
return;
}
opts = &context->listener->security_options;
}else{
opts = &db.config->security_options;
}
memset(&event_data, 0, sizeof(event_data));
event_data.client = context;
DL_FOREACH(opts->plugin_callbacks.connect, cb_base){
cb_base->cb(MOSQ_EVT_CONNECT, &event_data, cb_base->userdata);
@ -127,22 +117,24 @@ void plugin__handle_connect(struct mosquitto *context)
}
void plugin__handle_disconnect(struct mosquitto *context, int reason)
void plugin__handle_connect(struct mosquitto *context)
{
/* Global plugins */
plugin__handle_connect_single(&db.config->security_options, context);
/* Per listener plugins */
if(db.config->per_listener_settings && context->listener){
plugin__handle_connect_single(&context->listener->security_options, context);
}
}
static void plugin__handle_disconnect_single(struct mosquitto__security_options *opts, struct mosquitto *context, int reason)
{
struct mosquitto_evt_disconnect event_data;
struct mosquitto__callback *cb_base;
struct mosquitto__security_options *opts;
if(db.config->per_listener_settings){
if(context->listener == NULL){
return;
}
opts = &context->listener->security_options;
}else{
opts = &db.config->security_options;
}
memset(&event_data, 0, sizeof(event_data));
event_data.client = context;
event_data.reason = reason;
DL_FOREACH(opts->plugin_callbacks.disconnect, cb_base){
@ -151,26 +143,25 @@ void plugin__handle_disconnect(struct mosquitto *context, int reason)
}
int plugin__handle_message(struct mosquitto *context, struct mosquitto_msg_store *stored)
void plugin__handle_disconnect(struct mosquitto *context, int reason)
{
/* Global plugins */
plugin__handle_disconnect_single(&db.config->security_options, context, reason);
/* Per listener plugins */
if(db.config->per_listener_settings && context->listener){
plugin__handle_disconnect_single(&context->listener->security_options, context, reason);
}
}
static int plugin__handle_message_single(struct mosquitto__security_options *opts, 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;
@ -198,11 +189,40 @@ int plugin__handle_message(struct mosquitto *context, struct mosquitto_msg_store
return rc;
}
int plugin__handle_message(struct mosquitto *context, struct mosquitto_msg_store *stored)
{
int rc = MOSQ_ERR_SUCCESS;
void plugin__handle_tick(void)
/* Global plugins */
rc = plugin__handle_message_single(&db.config->security_options,
context, stored);
if(rc) return rc;
if(db.config->per_listener_settings && context->listener){
rc = plugin__handle_message_single(&context->listener->security_options,
context, stored);
}
return rc;
}
static void plugin__handle_tick_single(struct mosquitto__security_options *opts)
{
struct mosquitto_evt_tick event_data;
struct mosquitto__callback *cb_base;
/* FIXME - set now_s and now_ns to avoid need for multiple time lookups */
memset(&event_data, 0, sizeof(event_data));
DL_FOREACH(opts->plugin_callbacks.tick, cb_base){
cb_base->cb(MOSQ_EVT_TICK, &event_data, cb_base->userdata);
}
}
void plugin__handle_tick(void)
{
struct mosquitto__security_options *opts;
int i;
@ -211,20 +231,11 @@ void plugin__handle_tick(void)
for(i=0; i<db.config->listener_count; i++){
opts = &db.config->listeners[i].security_options;
if(opts && opts->plugin_callbacks.tick){
memset(&event_data, 0, sizeof(event_data));
DL_FOREACH(opts->plugin_callbacks.tick, cb_base){
cb_base->cb(MOSQ_EVT_TICK, &event_data, cb_base->userdata);
}
plugin__handle_tick_single(opts);
}
}
}else{
opts = &db.config->security_options;
memset(&event_data, 0, sizeof(event_data));
DL_FOREACH(opts->plugin_callbacks.tick, cb_base){
cb_base->cb(MOSQ_EVT_TICK, &event_data, cb_base->userdata);
}
plugin__handle_tick_single(&db.config->security_options);
}
}

@ -676,14 +676,47 @@ static int acl__check_dollar(const char *topic, int access)
}
static int plugin__acl_check(struct mosquitto__security_options *opts, struct mosquitto *context, const char *topic, uint32_t payloadlen, void* payload, uint8_t qos, bool retain, int access)
{
int rc = MOSQ_ERR_PLUGIN_DEFER;
struct mosquitto_acl_msg msg;
struct mosquitto__callback *cb_base;
struct mosquitto_evt_acl_check event_data;
memset(&msg, 0, sizeof(msg));
msg.topic = topic;
msg.payloadlen = payloadlen;
msg.payload = payload;
msg.qos = qos;
msg.retain = retain;
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;
}
}
return rc;
}
int mosquitto_acl_check(struct mosquitto *context, const char *topic, uint32_t payloadlen, void* payload, uint8_t qos, bool retain, int access)
{
int rc;
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;
@ -700,16 +733,34 @@ int mosquitto_acl_check(struct mosquitto *context, const char *topic, uint32_t p
*/
rc = MOSQ_ERR_SUCCESS;
if(db.config->security_options.plugin_callbacks.acl_check){
rc = plugin__acl_check(&db.config->security_options, context, topic, payloadlen,
payload, qos, retain, access);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
if(db.config->per_listener_settings){
if(context->listener){
opts = &context->listener->security_options;
if(context->listener->security_options.plugin_callbacks.acl_check){
rc = plugin__acl_check(&context->listener->security_options, context, topic, payloadlen,
payload, qos, retain, access);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
}else{
return MOSQ_ERR_ACL_DENIED;
}
opts = &context->listener->security_options;
}else{
opts = &db.config->security_options;
}
/* Old plugin version checks */
memset(&msg, 0, sizeof(msg));
msg.topic = topic;
msg.payloadlen = payloadlen;
@ -717,24 +768,6 @@ int mosquitto_acl_check(struct mosquitto *context, const char *topic, uint32_t p
msg.qos = qos;
msg.retain = retain;
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);
@ -752,13 +785,32 @@ int mosquitto_acl_check(struct mosquitto *context, const char *topic, uint32_t p
return rc;
}
static int plugin__unpwd_check(struct mosquitto__security_options *opts, struct mosquitto *context)
{
struct mosquitto_evt_basic_auth event_data;
struct mosquitto__callback *cb_base;
int rc = MOSQ_ERR_PLUGIN_DEFER;
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;
}
}
return rc;
}
int mosquitto_unpwd_check(struct mosquitto *context)
{
int rc;
int i;
struct mosquitto__security_options *opts;
struct mosquitto_evt_basic_auth event_data;
struct mosquitto__callback *cb_base;
bool plugin_used = false;
rc = MOSQ_ERR_PLUGIN_DEFER;
@ -772,18 +824,33 @@ int mosquitto_unpwd_check(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);
/* Global plugins */
if(db.config->security_options.plugin_callbacks.basic_auth){
rc = plugin__unpwd_check(&db.config->security_options, context);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
plugin_used = true;
}
/* Per listener plugins */
if(db.config->per_listener_settings){
if(context->listener == NULL){
return MOSQ_ERR_AUTH;
}
if(context->listener->security_options.plugin_callbacks.basic_auth){
rc = plugin__unpwd_check(&context->listener->security_options, context);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
plugin_used = true;
}
}
/* Old plugin checks */
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){
@ -838,13 +905,34 @@ int mosquitto_unpwd_check(struct mosquitto *context)
return rc;
}
static int plugin__psk_key_get(struct mosquitto__security_options *opts, struct mosquitto *context, const char *hint, const char *identity, char *key, int max_key_len)
{
struct mosquitto_evt_psk_key event_data;
struct mosquitto__callback *cb_base;
int rc = MOSQ_ERR_PLUGIN_DEFER;
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;
}
}
return rc;
}
int mosquitto_psk_key_get(struct mosquitto *context, const char *hint, const char *identity, char *key, int max_key_len)
{
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(context, hint, identity, key, max_key_len);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
@ -856,24 +944,40 @@ int mosquitto_psk_key_get(struct mosquitto *context, const char *hint, const cha
*/
if(db.config->per_listener_settings){
if(context->listener == NULL){
return MOSQ_ERR_AUTH;
}
opts = &context->listener->security_options;
}else{
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);
/* Global plugins */
if(db.config->security_options.plugin_callbacks.psk_key){
rc = plugin__psk_key_get(&db.config->security_options, context,
hint, identity, key, max_key_len);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
/* Per listener plugins */
if(db.config->per_listener_settings){
if(context->listener == NULL){
return MOSQ_ERR_AUTH;
}
if(context->listener->security_options.plugin_callbacks.psk_key){
rc = plugin__psk_key_get(&context->listener->security_options, context,
hint, identity, key, max_key_len);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
}
/* Old plugins */
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){
@ -919,22 +1023,13 @@ int mosquitto_psk_key_get(struct mosquitto *context, const char *hint, const cha
}
int mosquitto_security_auth_start(struct mosquitto *context, bool reauth, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len)
static int plugin__ext_auth_start(struct mosquitto__security_options *opts, struct mosquitto *context, bool reauth, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len)
{
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;
int rc = MOSQ_ERR_PLUGIN_DEFER;
if(!context || !context->listener || !context->auth_method) return MOSQ_ERR_INVAL;
if(!data_out || !data_out_len) return MOSQ_ERR_INVAL;
if(db.config->per_listener_settings){
opts = &context->listener->security_options;
}else{
opts = &db.config->security_options;
}
UNUSED(reauth);
DL_FOREACH(opts->plugin_callbacks.ext_auth_start, cb_base){
memset(&event_data, 0, sizeof(event_data));
@ -951,7 +1046,54 @@ int mosquitto_security_auth_start(struct mosquitto *context, bool reauth, const
return rc;
}
}
return rc;
}
int mosquitto_security_auth_start(struct mosquitto *context, bool reauth, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len)
{
int rc = MOSQ_ERR_PLUGIN_DEFER;
int i;
struct mosquitto__security_options *opts;
if(!context || !context->listener || !context->auth_method) return MOSQ_ERR_INVAL;
if(!data_out || !data_out_len) return MOSQ_ERR_INVAL;
if(db.config->per_listener_settings){
if(context->listener == NULL){
return MOSQ_ERR_AUTH;
}
opts = &context->listener->security_options;
}else{
opts = &db.config->security_options;
}
/* Global plugins */
if(db.config->security_options.plugin_callbacks.ext_auth_start){
rc = plugin__ext_auth_start(&db.config->security_options, context,
reauth, data_in, data_in_len, data_out, data_out_len);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
/* Per listener plugins */
if(db.config->per_listener_settings){
if(context->listener == NULL){
return MOSQ_ERR_AUTH;
}
if(context->listener->security_options.plugin_callbacks.ext_auth_start){
rc = plugin__ext_auth_start(&context->listener->security_options, context,
reauth, data_in, data_in_len, data_out, data_out_len);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
}
/* Old plugins */
for(i=0; i<opts->auth_plugin_config_count; i++){
if(opts->auth_plugin_configs[i].plugin.auth_start_v4){
*data_out = NULL;
@ -979,23 +1121,12 @@ int mosquitto_security_auth_start(struct mosquitto *context, bool reauth, const
}
int mosquitto_security_auth_continue(struct mosquitto *context, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len)
static int plugin__ext_auth_continue(struct mosquitto__security_options *opts, struct mosquitto *context, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len)
{
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;
if(db.config->per_listener_settings){
opts = &context->listener->security_options;
}else{
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;
@ -1010,7 +1141,54 @@ int mosquitto_security_auth_continue(struct mosquitto *context, const void *data
return rc;
}
}
return rc;
}
int mosquitto_security_auth_continue(struct mosquitto *context, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len)
{
int rc = MOSQ_ERR_PLUGIN_DEFER;
int i;
struct mosquitto__security_options *opts;
if(!context || !context->listener || !context->auth_method) return MOSQ_ERR_INVAL;
if(!data_out || !data_out_len) return MOSQ_ERR_INVAL;
if(db.config->per_listener_settings){
if(context->listener == NULL){
return MOSQ_ERR_AUTH;
}
opts = &context->listener->security_options;
}else{
opts = &db.config->security_options;
}
/* Global plugins */
if(db.config->security_options.plugin_callbacks.ext_auth_continue){
rc = plugin__ext_auth_continue(&db.config->security_options, context,
data_in, data_in_len, data_out, data_out_len);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
/* Per listener plugins */
if(db.config->per_listener_settings){
if(context->listener == NULL){
return MOSQ_ERR_AUTH;
}
if(context->listener->security_options.plugin_callbacks.ext_auth_continue){
rc = plugin__ext_auth_continue(&context->listener->security_options, context,
data_in, data_in_len, data_out, data_out_len);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
}
/* Old plugins */
for(i=0; i<opts->auth_plugin_config_count; i++){
if(opts->auth_plugin_configs[i].plugin.auth_continue_v4){
*data_out = NULL;

Loading…
Cancel
Save