mosquitto/src/security.c

616 lines
18 KiB
C
Raw Normal View History

2014-05-07 22:27:00 +00:00
/*
2018-04-11 14:24:29 +00:00
Copyright (c) 2011-2018 Roger Light <roger@atchoo.org>
2014-05-07 22:27:00 +00:00
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.
*/
2015-04-29 20:37:47 +00:00
#include "config.h"
2014-05-07 22:27:00 +00:00
#include <stdio.h>
#include <string.h>
#include "mosquitto_broker_internal.h"
2014-05-07 22:27:00 +00:00
#include "mosquitto_plugin.h"
2015-04-29 20:37:47 +00:00
#include "memory_mosq.h"
2014-05-07 22:27:00 +00:00
#include "lib_load.h"
typedef int (*FUNC_auth_plugin_version)(void);
2018-03-26 14:23:00 +00:00
static int security__cleanup_single(struct mosquitto__security_options *opts, bool reload);
2014-05-07 22:27:00 +00:00
void LIB_ERROR(void)
{
#ifdef WIN32
char *buf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
NULL, GetLastError(), LANG_NEUTRAL, &buf, 0, NULL);
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Load error: %s", buf);
LocalFree(buf);
#else
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Load error: %s", dlerror());
#endif
}
int security__load_v2(struct mosquitto_db *db, struct mosquitto__auth_plugin *plugin, struct mosquitto_auth_opt *auth_options, int auth_option_count, void *lib)
{
int rc;
if(!(plugin->plugin_init_v2 = (FUNC_auth_plugin_init_v2)LIB_SYM(lib, "mosquitto_auth_plugin_init"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_plugin_init().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->plugin_cleanup_v2 = (FUNC_auth_plugin_cleanup_v2)LIB_SYM(lib, "mosquitto_auth_plugin_cleanup"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_plugin_cleanup().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->security_init_v2 = (FUNC_auth_plugin_security_init_v2)LIB_SYM(lib, "mosquitto_auth_security_init"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_security_init().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->security_cleanup_v2 = (FUNC_auth_plugin_security_cleanup_v2)LIB_SYM(lib, "mosquitto_auth_security_cleanup"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_security_cleanup().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->acl_check_v2 = (FUNC_auth_plugin_acl_check_v2)LIB_SYM(lib, "mosquitto_auth_acl_check"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_acl_check().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->unpwd_check_v2 = (FUNC_auth_plugin_unpwd_check_v2)LIB_SYM(lib, "mosquitto_auth_unpwd_check"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_unpwd_check().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->psk_key_get_v2 = (FUNC_auth_plugin_psk_key_get_v2)LIB_SYM(lib, "mosquitto_auth_psk_key_get"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_psk_key_get().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
plugin->lib = lib;
plugin->user_data = NULL;
if(plugin->plugin_init_v2){
rc = plugin->plugin_init_v2(&plugin->user_data, auth_options, auth_option_count);
if(rc){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Authentication plugin returned %d when initialising.", rc);
return rc;
}
}
return 0;
}
int security__load_v3(struct mosquitto_db *db, struct mosquitto__auth_plugin *plugin, struct mosquitto_opt *auth_options, int auth_option_count, void *lib)
{
int rc;
if(!(plugin->plugin_init_v3 = (FUNC_auth_plugin_init_v3)LIB_SYM(lib, "mosquitto_auth_plugin_init"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_plugin_init().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->plugin_cleanup_v3 = (FUNC_auth_plugin_cleanup_v3)LIB_SYM(lib, "mosquitto_auth_plugin_cleanup"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_plugin_cleanup().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->security_init_v3 = (FUNC_auth_plugin_security_init_v3)LIB_SYM(lib, "mosquitto_auth_security_init"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_security_init().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->security_cleanup_v3 = (FUNC_auth_plugin_security_cleanup_v3)LIB_SYM(lib, "mosquitto_auth_security_cleanup"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_security_cleanup().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->acl_check_v3 = (FUNC_auth_plugin_acl_check_v3)LIB_SYM(lib, "mosquitto_auth_acl_check"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_acl_check().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->unpwd_check_v3 = (FUNC_auth_plugin_unpwd_check_v3)LIB_SYM(lib, "mosquitto_auth_unpwd_check"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_unpwd_check().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
if(!(plugin->psk_key_get_v3 = (FUNC_auth_plugin_psk_key_get_v3)LIB_SYM(lib, "mosquitto_auth_psk_key_get"))){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Unable to load auth plugin function mosquitto_auth_psk_key_get().");
LIB_ERROR();
LIB_CLOSE(lib);
return 1;
}
plugin->lib = lib;
plugin->user_data = NULL;
if(plugin->plugin_init_v3){
rc = plugin->plugin_init_v3(&plugin->user_data, auth_options, auth_option_count);
if(rc){
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Authentication plugin returned %d when initialising.", rc);
return rc;
}
}
return 0;
}
2018-03-26 14:23:00 +00:00
static int security__module_init_single(struct mosquitto_db *db, struct mosquitto__security_options *opts)
2014-05-07 22:27:00 +00:00
{
void *lib;
int (*plugin_version)(void) = NULL;
int version;
int i;
2018-03-26 14:23:00 +00:00
int rc;
2014-05-07 22:27:00 +00:00
2018-03-26 14:23:00 +00:00
if(opts->auth_plugin_config_count == 0){
return MOSQ_ERR_SUCCESS;
}
2014-05-07 22:27:00 +00:00
2018-03-26 14:23:00 +00:00
for(i=0; i<opts->auth_plugin_config_count; i++){
if(opts->auth_plugin_configs[i].path){
memset(&opts->auth_plugin_configs[i].plugin, 0, sizeof(struct mosquitto__auth_plugin));
lib = LIB_LOAD(opts->auth_plugin_configs[i].path);
if(!lib){
log__printf(NULL, MOSQ_LOG_ERR,
2018-03-26 14:23:00 +00:00
"Error: Unable to load auth plugin \"%s\".", opts->auth_plugin_configs[i].path);
LIB_ERROR();
return 1;
}
2014-05-07 22:27:00 +00:00
2018-03-26 14:23:00 +00:00
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;
}
version = plugin_version();
2018-03-26 14:23:00 +00:00
opts->auth_plugin_configs[i].plugin.version = version;
if(version == 3){
2018-03-26 14:23:00 +00:00
rc = security__load_v3(
db,
&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 == 2){
2018-03-26 14:23:00 +00:00
rc = security__load_v2(
db,
&opts->auth_plugin_configs[i].plugin,
(struct mosquitto_auth_opt *)opts->auth_plugin_configs[i].options,
opts->auth_plugin_configs[i].option_count,
lib);
if(rc){
return rc;
}
}else{
log__printf(NULL, MOSQ_LOG_ERR,
"Error: Incorrect auth plugin version (got %d, expected %d).",
version, MOSQ_AUTH_PLUGIN_VERSION);
LIB_ERROR();
2014-05-07 22:27:00 +00:00
LIB_CLOSE(lib);
return 1;
}
2014-05-07 22:27:00 +00:00
}
}
return MOSQ_ERR_SUCCESS;
}
2018-03-26 14:23:00 +00:00
int mosquitto_security_module_init(struct mosquitto_db *db)
{
2018-03-26 21:50:41 +00:00
int rc = MOSQ_ERR_SUCCESS;
2018-03-26 14:23:00 +00:00
int i;
if(db->config->per_listener_settings){
for(i=0; i<db->config->listener_count; i++){
rc = security__module_init_single(db, &db->config->listeners[i].security_options);
if(rc) return rc;
}
}else{
rc = security__module_init_single(db, &db->config->security_options);
}
return rc;
}
static void security__module_cleanup_single(struct mosquitto__security_options *opts)
{
int i;
for(i=0; i<opts->auth_plugin_config_count; i++){
/* Run plugin cleanup function */
if(opts->auth_plugin_configs[i].plugin.version == 3){
opts->auth_plugin_configs[i].plugin.plugin_cleanup_v3(
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 == 2){
opts->auth_plugin_configs[i].plugin.plugin_cleanup_v2(
opts->auth_plugin_configs[i].plugin.user_data,
(struct mosquitto_auth_opt *)opts->auth_plugin_configs[i].options,
opts->auth_plugin_configs[i].option_count);
}
2018-03-26 14:23:00 +00:00
if(opts->auth_plugin_configs[i].plugin.lib){
LIB_CLOSE(opts->auth_plugin_configs[i].plugin.lib);
}
memset(&opts->auth_plugin_configs[i].plugin, 0, sizeof(struct mosquitto__auth_plugin));
}
}
2014-05-07 22:27:00 +00:00
int mosquitto_security_module_cleanup(struct mosquitto_db *db)
{
int i;
2014-05-07 22:27:00 +00:00
mosquitto_security_cleanup(db, false);
2018-03-26 14:23:00 +00:00
security__module_cleanup_single(&db->config->security_options);
2014-05-07 22:27:00 +00:00
2018-03-26 14:23:00 +00:00
for(i=0; i<db->config->listener_count; i++){
security__module_cleanup_single(&db->config->listeners[i].security_options);
}
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_SUCCESS;
}
2018-03-26 14:23:00 +00:00
static int security__init_single(struct mosquitto__security_options *opts, bool reload)
2014-05-07 22:27:00 +00:00
{
int i;
int rc;
2018-03-26 14:23:00 +00:00
for(i=0; i<opts->auth_plugin_config_count; i++){
if(opts->auth_plugin_configs[i].plugin.version == 3){
rc = opts->auth_plugin_configs[i].plugin.security_init_v3(
opts->auth_plugin_configs[i].plugin.user_data,
opts->auth_plugin_configs[i].options,
opts->auth_plugin_configs[i].option_count,
reload);
}else if(opts->auth_plugin_configs[i].plugin.version == 2){
rc = opts->auth_plugin_configs[i].plugin.security_init_v2(
opts->auth_plugin_configs[i].plugin.user_data,
(struct mosquitto_auth_opt *)opts->auth_plugin_configs[i].options,
opts->auth_plugin_configs[i].option_count,
reload);
}else{
rc = MOSQ_ERR_INVAL;
}
if(rc != MOSQ_ERR_SUCCESS){
return rc;
}
2014-05-07 22:27:00 +00:00
}
2018-03-26 14:23:00 +00:00
return MOSQ_ERR_SUCCESS;
}
int mosquitto_security_init(struct mosquitto_db *db, bool reload)
{
int i;
int rc;
if(db->config->per_listener_settings){
for(i=0; i<db->config->listener_count; i++){
rc = security__init_single(&db->config->listeners[i].security_options, reload);
if(rc != MOSQ_ERR_SUCCESS) return rc;
}
}else{
rc = security__init_single(&db->config->security_options, reload);
if(rc != MOSQ_ERR_SUCCESS) return rc;
}
return mosquitto_security_init_default(db, reload);
2014-05-07 22:27:00 +00:00
}
/* Apply security settings after a reload.
* Includes:
* - Disconnecting anonymous users if appropriate
* - Disconnecting users with invalid passwords
* - Reapplying ACLs
*/
int mosquitto_security_apply(struct mosquitto_db *db)
{
return mosquitto_security_apply_default(db);
2014-05-07 22:27:00 +00:00
}
2018-03-26 14:23:00 +00:00
static int security__cleanup_single(struct mosquitto__security_options *opts, bool reload)
2014-05-07 22:27:00 +00:00
{
int i;
int rc;
2018-03-26 14:23:00 +00:00
for(i=0; i<opts->auth_plugin_config_count; i++){
if(opts->auth_plugin_configs[i].plugin.version == 3){
rc = opts->auth_plugin_configs[i].plugin.security_cleanup_v3(
opts->auth_plugin_configs[i].plugin.user_data,
opts->auth_plugin_configs[i].options,
opts->auth_plugin_configs[i].option_count,
reload);
}else if(opts->auth_plugin_configs[i].plugin.version == 2){
rc = opts->auth_plugin_configs[i].plugin.security_cleanup_v2(
opts->auth_plugin_configs[i].plugin.user_data,
(struct mosquitto_auth_opt *)opts->auth_plugin_configs[i].options,
opts->auth_plugin_configs[i].option_count,
reload);
}else{
rc = MOSQ_ERR_INVAL;
}
if(rc != MOSQ_ERR_SUCCESS){
return rc;
}
2014-05-07 22:27:00 +00:00
}
2018-03-26 14:23:00 +00:00
return MOSQ_ERR_SUCCESS;
}
int mosquitto_security_cleanup(struct mosquitto_db *db, bool reload)
{
int i;
int rc;
rc = security__cleanup_single(&db->config->security_options, reload);
if(rc != MOSQ_ERR_SUCCESS) return rc;
for(i=0; i<db->config->listener_count; i++){
rc = security__cleanup_single(&db->config->listeners[i].security_options, reload);
if(rc != MOSQ_ERR_SUCCESS) return rc;
}
return mosquitto_security_cleanup_default(db, reload);
2014-05-07 22:27:00 +00:00
}
2018-03-26 14:23:00 +00:00
//int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int access)
static int acl__check_single(struct mosquitto__auth_plugin_config *auth_plugin, struct mosquitto *context, struct mosquitto_acl_msg *msg, int access)
2018-03-26 14:23:00 +00:00
{
const char *username;
const char *topic = msg->topic;
2018-03-26 14:23:00 +00:00
username = mosquitto_client_username(context);
if(auth_plugin->deny_special_chars == true){
/* Check whether the client id or username contains a +, # or / and if
* so deny access.
*
* Do this check for every message regardless, we have to protect the
* plugins against possible pattern based attacks.
*/
if(username && strpbrk(username, "+#")){
log__printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous username \"%s\"", username);
return MOSQ_ERR_ACL_DENIED;
}
if(context->id && strpbrk(context->id, "+#")){
log__printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous client id \"%s\"", context->id);
return MOSQ_ERR_ACL_DENIED;
}
}
if(auth_plugin->plugin.version == 3){
return auth_plugin->plugin.acl_check_v3(auth_plugin->plugin.user_data, access, context, msg);
2018-03-26 14:23:00 +00:00
}else if(auth_plugin->plugin.version == 2){
if(access == MOSQ_ACL_SUBSCRIBE){
return MOSQ_ERR_SUCCESS;
}
return auth_plugin->plugin.acl_check_v2(auth_plugin->plugin.user_data, context->id, username, topic, access);
}else{
return MOSQ_ERR_INVAL;
}
}
int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, const char *topic, long payloadlen, void* payload, int qos, bool retain, int access)
2014-05-07 22:27:00 +00:00
{
int rc;
int i;
2018-03-26 14:23:00 +00:00
struct mosquitto__security_options *opts;
struct mosquitto_acl_msg msg;
2014-07-08 22:07:19 +00:00
if(!context->id){
return MOSQ_ERR_ACL_DENIED;
}
2015-10-02 20:44:39 +00:00
rc = mosquitto_acl_check_default(db, context, topic, access);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
2016-07-08 08:36:25 +00:00
/* Default check has accepted or deferred at this point.
2015-10-02 20:44:39 +00:00
* If no plugins exist we should accept at this point so set rc to success.
*/
rc = MOSQ_ERR_SUCCESS;
2017-05-31 20:05:26 +00:00
2018-03-26 14:23:00 +00:00
if(db->config->per_listener_settings){
opts = &context->listener->security_options;
}else{
opts = &db->config->security_options;
}
memset(&msg, 0, sizeof(msg));
msg.topic = topic;
msg.payloadlen = payloadlen;
msg.payload = payload;
msg.qos = qos;
msg.retain = retain;
2018-03-26 14:23:00 +00:00
for(i=0; i<opts->auth_plugin_config_count; i++){
rc = acl__check_single(&opts->auth_plugin_configs[i], context, &msg, access);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
2014-05-07 22:27:00 +00:00
}
2018-03-26 14:23:00 +00:00
2015-10-02 20:44:39 +00:00
/* 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){
rc = MOSQ_ERR_ACL_DENIED;
}
return rc;
2014-05-07 22:27:00 +00:00
}
2016-07-08 12:27:14 +00:00
int mosquitto_unpwd_check(struct mosquitto_db *db, struct mosquitto *context, const char *username, const char *password)
2014-05-07 22:27:00 +00:00
{
int rc;
int i;
2018-03-26 14:23:00 +00:00
struct mosquitto__security_options *opts;
2018-03-13 17:44:33 +00:00
rc = mosquitto_unpwd_check_default(db, context, username, password);
2015-10-02 20:44:39 +00:00
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
2016-07-08 08:36:25 +00:00
/* Default check has accepted or deferred at this point.
2015-10-02 20:44:39 +00:00
* If no plugins exist we should accept at this point so set rc to success.
*/
2018-03-26 14:23:00 +00:00
if(db->config->per_listener_settings){
opts = &context->listener->security_options;
}else{
opts = &db->config->security_options;
}
2015-10-02 20:44:39 +00:00
rc = MOSQ_ERR_SUCCESS;
2018-03-26 14:23:00 +00:00
for(i=0; i<opts->auth_plugin_config_count; i++){
if(opts->auth_plugin_configs[i].plugin.version == 3){
rc = opts->auth_plugin_configs[i].plugin.unpwd_check_v3(
opts->auth_plugin_configs[i].plugin.user_data,
context,
username,
password);
}else if(opts->auth_plugin_configs[i].plugin.version == 2){
rc = opts->auth_plugin_configs[i].plugin.unpwd_check_v2(
opts->auth_plugin_configs[i].plugin.user_data,
username,
password);
}else{
rc = MOSQ_ERR_INVAL;
}
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
2014-05-07 22:27:00 +00:00
}
2015-10-02 20:44:39 +00:00
/* 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){
rc = MOSQ_ERR_AUTH;
}
return rc;
2014-05-07 22:27:00 +00:00
}
2016-07-08 12:52:02 +00:00
int mosquitto_psk_key_get(struct mosquitto_db *db, struct mosquitto *context, const char *hint, const char *identity, char *key, int max_key_len)
2014-05-07 22:27:00 +00:00
{
int rc;
int i;
2018-03-26 14:23:00 +00:00
struct mosquitto__security_options *opts;
2018-03-15 21:39:42 +00:00
rc = mosquitto_psk_key_get_default(db, context, hint, identity, key, max_key_len);
2016-07-08 08:36:25 +00:00
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
/* Default check has accepted or deferred at this point.
* If no plugins exist we should accept at this point so set rc to success.
*/
2018-03-26 14:23:00 +00:00
if(db->config->per_listener_settings){
opts = &context->listener->security_options;
}else{
opts = &db->config->security_options;
}
for(i=0; i<opts->auth_plugin_config_count; i++){
if(opts->auth_plugin_configs[i].plugin.version == 3){
rc = opts->auth_plugin_configs[i].plugin.psk_key_get_v3(
opts->auth_plugin_configs[i].plugin.user_data,
context,
hint,
identity,
key,
max_key_len);
}else if(opts->auth_plugin_configs[i].plugin.version == 2){
rc = opts->auth_plugin_configs[i].plugin.psk_key_get_v2(
opts->auth_plugin_configs[i].plugin.user_data,
hint,
identity,
key,
max_key_len);
}else{
rc = MOSQ_ERR_INVAL;
}
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
2014-05-07 22:27:00 +00:00
}
2018-03-26 14:23:00 +00:00
2016-07-08 08:36:25 +00:00
/* 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){
rc = MOSQ_ERR_AUTH;
}
return rc;
2014-05-07 22:27:00 +00:00
}