diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml
index 98fc84e1..b3280cc7 100644
--- a/man/mosquitto.conf.5.xml
+++ b/man/mosquitto.conf.5.xml
@@ -80,9 +80,9 @@
authenticate using the MQTT username/password if using the
password_file option.
Both certificate and PSK based encryption are configured on a per-listener basis.
- Authentication plugins can be created to replace the
- password_file and psk_file options (as well as the ACL options)
- with e.g. SQL based lookups.
+ Authentication plugins can be created to augment the
+ password_file, acl_file and psk_file options with e.g. SQL based
+ lookups.It is possible to support multiple authentication schemes at
once. A config could be created that had a listener for all of the
different encryption options described above and hence a large
@@ -205,6 +205,12 @@
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 first. If a plugin is used but neither
+ of the default password or acl options are used, access
+ will be denied.Not currently reloaded on reload signal.
diff --git a/mosquitto.conf b/mosquitto.conf
index 6f3ff5a9..7eed801c 100644
--- a/mosquitto.conf
+++ b/mosquitto.conf
@@ -528,7 +528,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.
+# for alternative authentication options. If an auth_plugin is used as well as
+# password_file, the auth_plugin check will be made first.
#password_file
# Access may also be controlled using a pre-shared-key file. This requires
@@ -536,6 +537,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.
#psk_file
# Control access to topics on the broker using an access control list
@@ -585,6 +587,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.
#acl_file
# -----------------------------------------------------------------
@@ -597,7 +601,8 @@
#
# The auth_plugin option can be specified multiple times to load multiple
# plugins. The plugins will be processed in the order that they are specified
-# here.
+# here. If the auth_plugin option is specified alongside either of
+# password_file or acl_file then the plugin checks will be made first.
#
#auth_plugin
diff --git a/src/mosquitto_plugin.h b/src/mosquitto_plugin.h
index 0bf0f169..388dbe89 100644
--- a/src/mosquitto_plugin.h
+++ b/src/mosquitto_plugin.h
@@ -38,7 +38,20 @@ struct mosquitto_auth_opt {
*
* Authentication plugins can implement one or both of authentication and
* access control. If your plugin does not wish to handle either of
- * authentication or access control it should return MOSQ_ERR_DEFER.
+ * authentication or access control it should return MOSQ_ERR_DEFER. In this
+ * case, the next plugin will handle it. If all plugins return MOSQ_ERR_DEFER,
+ * the request will be denied.
+ *
+ * For each check, the following flow happens:
+ *
+ * * First plugin does the check, if it returns anything other than
+ * MOSQ_ERR_DEFER, then the check returns immediately. If the plugin returns
+ * MOSQ_ERR_DEFER then the next plugin runs its check.
+ * * If the final plugin returns MOSQ_ERR_DEFER, then the default password file
+ * and/or acl file check will be made if they are specified in the config
+ * file.
+ * * If plugins are defined and the password file and/or acl file are not
+ * specified, then the request will be denied.
*/
/* =========================================================================
@@ -228,7 +241,7 @@ int mosquitto_auth_unpwd_check(void *user_data, const char *username, const char
* Return value:
* Return 0 on success.
* Return >0 on failure.
- * Return >0 if this function is not required.
+ * Return MOSQ_ERR_DEFER if your plugin does not wish to handle this check.
*/
int mosquitto_auth_psk_key_get(void *user_data, const char *hint, const char *identity, char *key, int max_key_len);
diff --git a/src/plugin_defer.c b/src/plugin_defer.c
new file mode 100644
index 00000000..9f895ae4
--- /dev/null
+++ b/src/plugin_defer.c
@@ -0,0 +1,61 @@
+/*
+Copyright (c) 2015 Roger Light
+
+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.
+*/
+
+/* This is a skeleton authentication and access control plugin that simply defers all checks. */
+
+#include "mosquitto_plugin.h"
+#include "mosquitto.h"
+
+int mosquitto_auth_plugin_version(void)
+{
+ return MOSQ_AUTH_PLUGIN_VERSION;
+}
+
+int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count)
+{
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_auth_plugin_cleanup(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count)
+{
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_auth_security_init(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count, bool reload)
+{
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_auth_security_cleanup(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count, bool reload)
+{
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto_auth_acl_check(void *user_data, const char *clientid, const char *username, const char *topic, int access)
+{
+ return MOSQ_ERR_DEFER;
+}
+
+int mosquitto_auth_unpwd_check(void *user_data, const char *username, const char *password)
+{
+ return MOSQ_ERR_DEFER;
+}
+
+int mosquitto_auth_psk_key_get(void *user_data, const char *hint, const char *identity, char *key, int max_key_len)
+{
+ return MOSQ_ERR_DEFER;
+}
+
diff --git a/src/security.c b/src/security.c
index 648ac8a1..9f388dea 100644
--- a/src/security.c
+++ b/src/security.c
@@ -197,18 +197,13 @@ int mosquitto_security_init(struct mosquitto_db *db, bool reload)
int i;
int rc;
- if(!db->auth_plugins){
- return mosquitto_security_init_default(db, reload);
- }else{
- for(i=0; iconfig->auth_plugin_count; i++){
- rc = db->auth_plugins[i].security_init(db->auth_plugins[i].user_data, db->config->auth_plugins[i].options, db->config->auth_plugins[i].option_count, reload);
- if(rc != MOSQ_ERR_SUCCESS){
- return rc;
- }
+ for(i=0; iconfig->auth_plugin_count; i++){
+ rc = db->auth_plugins[i].security_init(db->auth_plugins[i].user_data, db->config->auth_plugins[i].options, db->config->auth_plugins[i].option_count, reload);
+ if(rc != MOSQ_ERR_SUCCESS){
+ return rc;
}
}
-
- return MOSQ_ERR_SUCCESS;
+ return mosquitto_security_init_default(db, reload);
}
/* Apply security settings after a reload.
@@ -219,10 +214,7 @@ int mosquitto_security_init(struct mosquitto_db *db, bool reload)
*/
int mosquitto_security_apply(struct mosquitto_db *db)
{
- if(!db->auth_plugins){
- return mosquitto_security_apply_default(db);
- }
- return MOSQ_ERR_SUCCESS;
+ return mosquitto_security_apply_default(db);
}
int mosquitto_security_cleanup(struct mosquitto_db *db, bool reload)
@@ -230,17 +222,13 @@ int mosquitto_security_cleanup(struct mosquitto_db *db, bool reload)
int i;
int rc;
- if(!db->auth_plugins){
- return mosquitto_security_cleanup_default(db, reload);
- }else{
- for(i=0; iconfig->auth_plugin_count; i++){
- rc = db->auth_plugins[i].security_cleanup(db->auth_plugins[i].user_data, db->config->auth_plugins[i].options, db->config->auth_plugins[i].option_count, reload);
- if(rc != MOSQ_ERR_SUCCESS){
- return rc;
- }
+ for(i=0; iconfig->auth_plugin_count; i++){
+ rc = db->auth_plugins[i].security_cleanup(db->auth_plugins[i].user_data, db->config->auth_plugins[i].options, db->config->auth_plugins[i].option_count, reload);
+ if(rc != MOSQ_ERR_SUCCESS){
+ return rc;
}
}
- return MOSQ_ERR_SUCCESS;
+ return mosquitto_security_cleanup_default(db, reload);
}
int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int access)
@@ -252,25 +240,22 @@ int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, cons
if(!context->id){
return MOSQ_ERR_ACL_DENIED;
}
- if(!db->auth_plugins){
- return mosquitto_acl_check_default(db, context, topic, access);
- }else{
+
#ifdef WITH_BRIDGE
- if(context->bridge){
- username = context->bridge->local_username;
- }else
+ if(context->bridge){
+ username = context->bridge->local_username;
+ }else
#endif
- {
- username = context->username;
- }
- for(i=0; iauth_plugin_count; i++){
- rc = db->auth_plugins[i].acl_check(db->auth_plugins[i].user_data, context->id, username, topic, access);
- if(rc != MOSQ_ERR_PLUGIN_DEFER){
- return rc;
- }
+ {
+ username = context->username;
+ }
+ for(i=0; iauth_plugin_count; i++){
+ rc = db->auth_plugins[i].acl_check(db->auth_plugins[i].user_data, context->id, username, topic, access);
+ if(rc != MOSQ_ERR_PLUGIN_DEFER){
+ return rc;
}
}
- return MOSQ_ERR_ACL_DENIED;
+ return mosquitto_acl_check_default(db, context, topic, access);
}
int mosquitto_unpwd_check(struct mosquitto_db *db, const char *username, const char *password)
@@ -278,17 +263,13 @@ int mosquitto_unpwd_check(struct mosquitto_db *db, const char *username, const c
int rc;
int i;
- if(!db->auth_plugins){
- return mosquitto_unpwd_check_default(db, username, password);
- }else{
- for(i=0; iauth_plugin_count; i++){
- rc = db->auth_plugins[i].unpwd_check(db->auth_plugins[i].user_data, username, password);
- if(rc != MOSQ_ERR_PLUGIN_DEFER){
- return rc;
- }
+ for(i=0; iauth_plugin_count; i++){
+ rc = db->auth_plugins[i].unpwd_check(db->auth_plugins[i].user_data, username, password);
+ if(rc != MOSQ_ERR_PLUGIN_DEFER){
+ return rc;
}
}
- return MOSQ_ERR_AUTH;
+ return mosquitto_unpwd_check_default(db, username, password);
}
int mosquitto_psk_key_get(struct mosquitto_db *db, const char *hint, const char *identity, char *key, int max_key_len)
@@ -296,16 +277,12 @@ int mosquitto_psk_key_get(struct mosquitto_db *db, const char *hint, const char
int rc;
int i;
- if(!db->auth_plugins){
- return mosquitto_psk_key_get_default(db, hint, identity, key, max_key_len);
- }else{
- for(i=0; iauth_plugin_count; i++){
- rc = db->auth_plugins[i].psk_key_get(db->auth_plugins[i].user_data, hint, identity, key, max_key_len);
- if(rc != MOSQ_ERR_PLUGIN_DEFER){
- return rc;
- }
+ for(i=0; iauth_plugin_count; i++){
+ rc = db->auth_plugins[i].psk_key_get(db->auth_plugins[i].user_data, hint, identity, key, max_key_len);
+ if(rc != MOSQ_ERR_PLUGIN_DEFER){
+ return rc;
}
}
- return MOSQ_ERR_AUTH;
+ return mosquitto_psk_key_get_default(db, hint, identity, key, max_key_len);
}
diff --git a/src/security_default.c b/src/security_default.c
index 5a5d4581..0bdf153b 100644
--- a/src/security_default.c
+++ b/src/security_default.c
@@ -231,7 +231,7 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte
char *s;
if(!db || !context || !topic) return MOSQ_ERR_INVAL;
- if(!db->acl_list && !db->acl_patterns) return MOSQ_ERR_SUCCESS;
+ if(!db->acl_list && !db->acl_patterns && !db->auth_plugins) return MOSQ_ERR_SUCCESS;
if(context->bridge) return MOSQ_ERR_SUCCESS;
if(!context->acl_list && !db->acl_patterns) return MOSQ_ERR_ACL_DENIED;
@@ -639,7 +639,7 @@ int mosquitto_unpwd_check_default(struct mosquitto_db *db, const char *username,
#endif
if(!db) return MOSQ_ERR_INVAL;
- if(!db->unpwd) return MOSQ_ERR_SUCCESS;
+ if(!db->unpwd && !db->auth_plugins) return MOSQ_ERR_SUCCESS;
if(!username) return MOSQ_ERR_INVAL; /* Check must be made only after checking db->unpwd. */
HASH_ITER(hh, db->unpwd, u, tmp){