From 40b402e64a417429432b7bf446fd2ca236791e7d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 28 Jul 2021 16:49:46 +0100 Subject: [PATCH] Add the `global_plugin` option. This gives global plugin loaded regardless of `per_listener_settings`. --- ChangeLog.txt | 2 + man/mosquitto.conf.5.xml | 144 +++++++++++-------- mosquitto.conf | 50 ++++--- src/conf.c | 11 +- src/plugin.c | 107 +++++++------- src/security.c | 304 +++++++++++++++++++++++++++++++-------- 6 files changed, 430 insertions(+), 188 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index c51f4ad8..ef182544 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -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 diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index 2fc95356..9d36300c 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -205,9 +205,9 @@ [ true | false ] - This option is deprecated and will be removed in a - future version. The behaviour will default to true. - + This option is deprecated and will be removed in a + future version. The behaviour will default to true. + 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 @@ Reloaded on reload signal. - - value - - Options to be passed to the auth plugin. See the - specific plugin instructions. - - Applies to the current authentication plugin being configured. - - - - file path - - Specify an external module to use for authentication - and access control. This allows custom - username/password and access control functions to be - created. - Can be specified multiple times to load multiple - plugins. The plugins will be processed in the order - that they are specified. - If , or - are used in the config file - alongsize , the plugin - checks will run after the built in checks. - Not currently reloaded on reload signal. - See also - - - - [ true | false ] @@ -382,8 +353,8 @@ prefix - This option is deprecated and will be removed in a - future version. + This option is deprecated and will be removed in a + future version. 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 @@ Reloaded on reload signal. + + file path + + + Load an external module to extend broker features. This loads plugins + for use across all listeners, regardless of the value of the + option. This option functions + the same as the option in all other ways. + + + + If you set , then define both a + and a (which will be + attached to a specific listener), then the global plugin will always be + processed first. + + + + If you set , then + behaves identically to + . + + + dir @@ -781,7 +776,7 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S , , , , - , + , , . 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 Not reloaded on reload signal. + + value + value + + Options to be passed to a plugin. See the + specific plugin instructions. + + Applies to the current plugin/global_plugin being configured. + + + + file path + file path + + 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. + Can be specified multiple times to load multiple + plugins. The plugins will be processed in the order + that they are specified. + If , or + are used in the config file + alongsize , the plugin + checks will run after the built in checks. + Not currently reloaded on reload signal. + + If is set to + true, this plugin will be + loaded for the current listener only. + + See also + + and the option. + + + file path @@ -1022,9 +1054,9 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S address - This option is deprecated and will be removed in a + This option is deprecated and will be removed in a future version. Use the instead. - + 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 port number - This option is deprecated and will be removed in a + This option is deprecated and will be removed in a future version. Use the instead. - + Set the network port for the default listener to listen on. Defaults to 1883. Not reloaded on reload signal. @@ -1331,21 +1363,21 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S cipher:list - - 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. - + + 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. + cipher:list - - The list of allowed ciphersuites for this listener, - for TLS v1.3, each separated with a colon. - + + The list of allowed ciphersuites for this listener, + for TLS v1.3, each separated with a colon. + @@ -1649,15 +1681,15 @@ openssl dhparam -out dhparam.pem 2048 idle interval counter - - 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. + + 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. - 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. Disabled by default. diff --git a/mosquitto.conf b/mosquitto.conf index 51c72fd3..36bcb1c4 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -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 -# 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 # ================================================================= # Bridges diff --git a/src/conf.c b/src/conf.c index 94a4d29b..f7c08100 100644 --- a/src/conf.c +++ b/src/conf.c @@ -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."); diff --git a/src/plugin.c b/src/plugin.c index b44c235a..07f4214a 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -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; ilistener_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); } } diff --git a/src/security.c b/src/security.c index 1f51d72b..239c9974 100644 --- a/src/security.c +++ b/src/security.c @@ -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; iauth_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; iauth_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; iauth_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; iauth_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; iauth_plugin_config_count; i++){ if(opts->auth_plugin_configs[i].plugin.auth_continue_v4){ *data_out = NULL;