2014-05-07 22:27:00 +00:00
|
|
|
/*
|
2015-04-19 21:10:59 +00:00
|
|
|
Copyright (c) 2011-2015 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>
|
|
|
|
|
2015-04-29 20:37:47 +00:00
|
|
|
#include "mosquitto_broker.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);
|
|
|
|
typedef int (*FUNC_auth_plugin_init)(void **, struct mosquitto_auth_opt *, int);
|
|
|
|
typedef int (*FUNC_auth_plugin_cleanup)(void *, struct mosquitto_auth_opt *, int);
|
|
|
|
typedef int (*FUNC_auth_plugin_security_init)(void *, struct mosquitto_auth_opt *, int, bool);
|
|
|
|
typedef int (*FUNC_auth_plugin_security_cleanup)(void *, struct mosquitto_auth_opt *, int, bool);
|
|
|
|
typedef int (*FUNC_auth_plugin_acl_check)(void *, const char *, const char *, const char *, int);
|
|
|
|
typedef int (*FUNC_auth_plugin_unpwd_check)(void *, const char *, const char *);
|
|
|
|
typedef int (*FUNC_auth_plugin_psk_key_get)(void *, const char *, const char *, char *, int);
|
|
|
|
|
2014-11-20 22:33:40 +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);
|
2014-11-20 22:33:40 +00:00
|
|
|
LocalFree(buf);
|
|
|
|
#else
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Load error: %s", dlerror());
|
2014-11-20 22:33:40 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-05-07 22:27:00 +00:00
|
|
|
int mosquitto_security_module_init(struct mosquitto_db *db)
|
|
|
|
{
|
|
|
|
void *lib;
|
|
|
|
int (*plugin_version)(void) = NULL;
|
|
|
|
int version;
|
|
|
|
int rc;
|
2015-06-29 21:22:28 +00:00
|
|
|
int i;
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-06-29 21:22:28 +00:00
|
|
|
if(db->config->auth_plugin_count == 0){
|
|
|
|
db->auth_plugins = NULL;
|
|
|
|
db->auth_plugin_count = 0;
|
|
|
|
}else{
|
|
|
|
db->auth_plugin_count = db->config->auth_plugin_count;
|
|
|
|
db->auth_plugins = mosquitto__calloc(db->auth_plugin_count, sizeof(struct mosquitto__auth_plugin));
|
|
|
|
if(!db->auth_plugins){
|
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
|
2014-05-07 22:27:00 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2015-06-29 21:22:28 +00:00
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-06-29 21:22:28 +00:00
|
|
|
for(i=0; i<db->config->auth_plugin_count; i++){
|
|
|
|
if(db->config->auth_plugins[i].path){
|
|
|
|
lib = LIB_LOAD(db->config->auth_plugins[i].path);
|
|
|
|
if(!lib){
|
|
|
|
log__printf(NULL, MOSQ_LOG_ERR,
|
|
|
|
"Error: Unable to load auth plugin \"%s\".", db->config->auth_plugins[i].path);
|
|
|
|
LIB_ERROR();
|
|
|
|
return 1;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-06-29 21:22:28 +00:00
|
|
|
db->auth_plugins[i].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();
|
|
|
|
if(version != MOSQ_AUTH_PLUGIN_VERSION){
|
|
|
|
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
|
|
|
|
2015-06-29 21:22:28 +00:00
|
|
|
LIB_CLOSE(lib);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if(!(db->auth_plugins[i].plugin_init = (FUNC_auth_plugin_init)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(!(db->auth_plugins[i].plugin_cleanup = (FUNC_auth_plugin_cleanup)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;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-06-29 21:22:28 +00:00
|
|
|
if(!(db->auth_plugins[i].security_init = (FUNC_auth_plugin_security_init)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;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-06-29 21:22:28 +00:00
|
|
|
if(!(db->auth_plugins[i].security_cleanup = (FUNC_auth_plugin_security_cleanup)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;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-06-29 21:22:28 +00:00
|
|
|
if(!(db->auth_plugins[i].acl_check = (FUNC_auth_plugin_acl_check)LIB_SYM(lib, "mosquitto_auth_acl_check"))){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR,
|
2015-06-29 21:22:28 +00:00
|
|
|
"Error: Unable to load auth plugin function mosquitto_auth_acl_check().");
|
|
|
|
LIB_ERROR();
|
|
|
|
LIB_CLOSE(lib);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(db->auth_plugins[i].unpwd_check = (FUNC_auth_plugin_unpwd_check)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(!(db->auth_plugins[i].psk_key_get = (FUNC_auth_plugin_psk_key_get)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;
|
|
|
|
}
|
|
|
|
|
|
|
|
db->auth_plugins[i].lib = lib;
|
|
|
|
db->auth_plugins[i].user_data = NULL;
|
|
|
|
if(db->auth_plugins[i].plugin_init){
|
|
|
|
rc = db->auth_plugins[i].plugin_init(&db->auth_plugins[i].user_data, db->config->auth_plugins[i].options, db->config->auth_plugins[i].option_count);
|
|
|
|
if(rc){
|
|
|
|
log__printf(NULL, MOSQ_LOG_ERR,
|
|
|
|
"Error: Authentication plugin returned %d when initialising.", rc);
|
2015-07-02 09:26:57 +00:00
|
|
|
return rc;
|
2015-06-29 21:22:28 +00:00
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mosquitto_security_module_cleanup(struct mosquitto_db *db)
|
|
|
|
{
|
2015-06-29 21:22:28 +00:00
|
|
|
int i;
|
|
|
|
|
2014-05-07 22:27:00 +00:00
|
|
|
mosquitto_security_cleanup(db, false);
|
|
|
|
|
2015-06-29 21:22:28 +00:00
|
|
|
for(i=0; i<db->config->auth_plugin_count; i++){
|
|
|
|
if(db->auth_plugins[i].plugin_cleanup){
|
|
|
|
db->auth_plugins[i].plugin_cleanup(db->auth_plugins[i].user_data, db->config->auth_plugins[i].options, db->config->auth_plugins[i].option_count);
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-06-29 21:22:28 +00:00
|
|
|
if(db->auth_plugins[i].lib){
|
|
|
|
LIB_CLOSE(db->auth_plugins[i].lib);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
2015-06-29 21:22:28 +00:00
|
|
|
db->auth_plugins[i].lib = NULL;
|
|
|
|
db->auth_plugins[i].plugin_init = NULL;
|
|
|
|
db->auth_plugins[i].plugin_cleanup = NULL;
|
|
|
|
db->auth_plugins[i].security_init = NULL;
|
|
|
|
db->auth_plugins[i].security_cleanup = NULL;
|
|
|
|
db->auth_plugins[i].acl_check = NULL;
|
|
|
|
db->auth_plugins[i].unpwd_check = NULL;
|
|
|
|
db->auth_plugins[i].psk_key_get = NULL;
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
2016-03-18 11:54:36 +00:00
|
|
|
mosquitto__free(db->auth_plugins);
|
|
|
|
db->auth_plugins = NULL;
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mosquitto_security_init(struct mosquitto_db *db, bool reload)
|
|
|
|
{
|
2015-06-29 21:22:28 +00:00
|
|
|
int i;
|
|
|
|
int rc;
|
|
|
|
|
2015-06-29 22:31:39 +00:00
|
|
|
for(i=0; i<db->config->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;
|
2015-06-29 21:22:28 +00:00
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
2015-06-29 22:31:39 +00:00
|
|
|
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)
|
|
|
|
{
|
2015-06-29 22:31:39 +00:00
|
|
|
return mosquitto_security_apply_default(db);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int mosquitto_security_cleanup(struct mosquitto_db *db, bool reload)
|
|
|
|
{
|
2015-06-29 21:22:28 +00:00
|
|
|
int i;
|
|
|
|
int rc;
|
|
|
|
|
2015-06-29 22:31:39 +00:00
|
|
|
for(i=0; i<db->config->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;
|
2015-06-29 21:22:28 +00:00
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
2015-06-29 22:31:39 +00:00
|
|
|
return mosquitto_security_cleanup_default(db, reload);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int access)
|
|
|
|
{
|
2014-10-29 22:11:18 +00:00
|
|
|
char *username;
|
2015-06-29 21:22:28 +00:00
|
|
|
int rc;
|
|
|
|
int i;
|
2014-10-29 22:11:18 +00:00
|
|
|
|
2014-07-08 22:07:19 +00:00
|
|
|
if(!context->id){
|
|
|
|
return MOSQ_ERR_ACL_DENIED;
|
|
|
|
}
|
2015-06-29 22:31:39 +00:00
|
|
|
|
2014-10-29 22:11:18 +00:00
|
|
|
#ifdef WITH_BRIDGE
|
2015-06-29 22:31:39 +00:00
|
|
|
if(context->bridge){
|
|
|
|
username = context->bridge->local_username;
|
|
|
|
}else
|
2014-10-29 22:11:18 +00:00
|
|
|
#endif
|
2015-06-29 22:31:39 +00:00
|
|
|
{
|
|
|
|
username = context->username;
|
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
/* Default check has accepted or errored and then returned, or deferred.
|
|
|
|
* If no plugins exist we should accept at this point so set rc to success.
|
|
|
|
*/
|
|
|
|
rc = MOSQ_ERR_SUCCESS;
|
2015-06-29 22:31:39 +00:00
|
|
|
for(i=0; i<db->auth_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;
|
2015-06-29 21:22:28 +00:00
|
|
|
}
|
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_ACL_DENIED;
|
|
|
|
}
|
|
|
|
return rc;
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int mosquitto_unpwd_check(struct mosquitto_db *db, const char *username, const char *password)
|
|
|
|
{
|
2015-06-29 21:22:28 +00:00
|
|
|
int rc;
|
|
|
|
int i;
|
|
|
|
|
2015-10-02 20:44:39 +00:00
|
|
|
rc = mosquitto_unpwd_check_default(db, username, password);
|
|
|
|
if(rc != MOSQ_ERR_PLUGIN_DEFER){
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
/* Default check has accepted or errored and then returned, or deferred.
|
|
|
|
* If no plugins exist we should accept at this point so set rc to success.
|
|
|
|
*/
|
|
|
|
rc = MOSQ_ERR_SUCCESS;
|
2015-06-29 22:31:39 +00:00
|
|
|
for(i=0; i<db->auth_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;
|
2015-06-29 21:22:28 +00:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
|
|
|
int mosquitto_psk_key_get(struct mosquitto_db *db, const char *hint, const char *identity, char *key, int max_key_len)
|
|
|
|
{
|
2015-06-29 21:22:28 +00:00
|
|
|
int rc;
|
|
|
|
int i;
|
|
|
|
|
2015-06-29 22:31:39 +00:00
|
|
|
for(i=0; i<db->auth_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;
|
2015-06-29 21:22:28 +00:00
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
2015-06-29 22:31:39 +00:00
|
|
|
return mosquitto_psk_key_get_default(db, hint, identity, key, max_key_len);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
|