From e773ea1beea3d4bef959a931a48c2786fe64ba26 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 29 Jun 2015 23:31:39 +0100 Subject: [PATCH] [464543] Run default checks after plugins. --- man/mosquitto.conf.5.xml | 12 ++++-- mosquitto.conf | 9 +++- src/mosquitto_plugin.h | 17 +++++++- src/plugin_defer.c | 61 +++++++++++++++++++++++++++ src/security.c | 89 +++++++++++++++------------------------- src/security_default.c | 4 +- 6 files changed, 127 insertions(+), 65 deletions(-) create mode 100644 src/plugin_defer.c 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){