mirror of
https://github.com/eclipse-mosquitto/mosquitto.git
synced 2026-02-06 02:52:07 +08:00
Move config load/save to own file.
This commit is contained in:
@@ -22,6 +22,7 @@ if(CJSON_FOUND AND WITH_TLS)
|
||||
../../lib/base64_mosq.c ../../lib/base64_mosq.h
|
||||
clients.c
|
||||
clientlist.c
|
||||
config.c
|
||||
config_init.c
|
||||
dynamic_security.h
|
||||
groups.c
|
||||
|
||||
@@ -14,6 +14,7 @@ OBJS= \
|
||||
base64_mosq.o \
|
||||
clients.o \
|
||||
clientlist.o \
|
||||
config.o \
|
||||
config_init.o \
|
||||
groups.o \
|
||||
grouplist.o \
|
||||
@@ -56,6 +57,9 @@ clients.o : clients.c dynamic_security.h
|
||||
clientlist.o : clientlist.c dynamic_security.h
|
||||
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) -c $< -o $@
|
||||
|
||||
config.o : config.c dynamic_security.h
|
||||
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) -c $< -o $@
|
||||
|
||||
config_init.o : config_init.c dynamic_security.h
|
||||
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) -c $< -o $@
|
||||
|
||||
|
||||
226
plugins/dynamic-security/config.c
Normal file
226
plugins/dynamic-security/config.c
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
Copyright (c) 2020-2021 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License 2.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cjson/cJSON.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "json_help.h"
|
||||
#include "mosquitto.h"
|
||||
#include "mosquitto_broker.h"
|
||||
#include "mosquitto_plugin.h"
|
||||
#include "mqtt_protocol.h"
|
||||
|
||||
#include "dynamic_security.h"
|
||||
|
||||
static int dynsec__general_config_load(cJSON *tree)
|
||||
{
|
||||
cJSON *j_default_access, *jtmp;
|
||||
|
||||
j_default_access = cJSON_GetObjectItem(tree, "defaultACLAccess");
|
||||
if(j_default_access && cJSON_IsObject(j_default_access)){
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_PUB_C_SEND);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.publish_c_send = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.publish_c_send = false;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_PUB_C_RECV);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.publish_c_recv = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.publish_c_recv = false;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_SUB_GENERIC);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.subscribe = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.subscribe = false;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_UNSUB_GENERIC);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.unsubscribe = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.unsubscribe = false;
|
||||
}
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static int dynsec__general_config_save(cJSON *tree)
|
||||
{
|
||||
cJSON *j_default_access;
|
||||
|
||||
j_default_access = cJSON_CreateObject();
|
||||
if(j_default_access == NULL){
|
||||
return 1;
|
||||
}
|
||||
cJSON_AddItemToObject(tree, "defaultACLAccess", j_default_access);
|
||||
|
||||
if(cJSON_AddBoolToObject(j_default_access, ACL_TYPE_PUB_C_SEND, default_access.publish_c_send) == NULL
|
||||
|| cJSON_AddBoolToObject(j_default_access, ACL_TYPE_PUB_C_RECV, default_access.publish_c_recv) == NULL
|
||||
|| cJSON_AddBoolToObject(j_default_access, ACL_TYPE_SUB_GENERIC, default_access.subscribe) == NULL
|
||||
|| cJSON_AddBoolToObject(j_default_access, ACL_TYPE_UNSUB_GENERIC, default_access.unsubscribe) == NULL
|
||||
){
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int dynsec__config_load(void)
|
||||
{
|
||||
FILE *fptr;
|
||||
long flen_l;
|
||||
size_t flen;
|
||||
char *json_str;
|
||||
cJSON *tree;
|
||||
|
||||
/* Load from file */
|
||||
fptr = fopen(g_config_file, "rb");
|
||||
if(fptr == NULL){
|
||||
/* Attempt to initialise a new config file */
|
||||
if(dynsec__config_init(g_config_file) == MOSQ_ERR_SUCCESS){
|
||||
mosquitto_log_printf(MOSQ_LOG_INFO, "Dynamic security plugin config not found, generating a default config.");
|
||||
mosquitto_log_printf(MOSQ_LOG_INFO, " Generated passwords are at %s.pw", g_config_file);
|
||||
/* If it works, try to open the file again */
|
||||
fptr = fopen(g_config_file, "rb");
|
||||
}
|
||||
|
||||
if(fptr == NULL){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR,
|
||||
"Error loading Dynamic security plugin config: File is not readable - check permissions.");
|
||||
return MOSQ_ERR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
fseek(fptr, 0, SEEK_END);
|
||||
flen_l = ftell(fptr);
|
||||
if(flen_l < 0){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: %s", strerror(errno));
|
||||
fclose(fptr);
|
||||
return 1;
|
||||
}else if(flen_l == 0){
|
||||
fclose(fptr);
|
||||
return 0;
|
||||
}
|
||||
flen = (size_t)flen_l;
|
||||
fseek(fptr, 0, SEEK_SET);
|
||||
json_str = mosquitto_calloc(flen+1, sizeof(char));
|
||||
if(json_str == NULL){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory.");
|
||||
fclose(fptr);
|
||||
return 1;
|
||||
}
|
||||
if(fread(json_str, 1, flen, fptr) != flen){
|
||||
mosquitto_log_printf(MOSQ_LOG_WARNING, "Error loading Dynamic security plugin config: Unable to read file contents.\n");
|
||||
mosquitto_free(json_str);
|
||||
fclose(fptr);
|
||||
return 1;
|
||||
}
|
||||
fclose(fptr);
|
||||
|
||||
tree = cJSON_Parse(json_str);
|
||||
mosquitto_free(json_str);
|
||||
if(tree == NULL){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: File is not valid JSON.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(dynsec__general_config_load(tree)
|
||||
|| dynsec_roles__config_load(tree)
|
||||
|| dynsec_clients__config_load(tree)
|
||||
|| dynsec_groups__config_load(tree)
|
||||
){
|
||||
|
||||
cJSON_Delete(tree);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cJSON_Delete(tree);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void dynsec__config_save(void)
|
||||
{
|
||||
cJSON *tree;
|
||||
size_t file_path_len;
|
||||
char *file_path;
|
||||
FILE *fptr;
|
||||
size_t json_str_len;
|
||||
char *json_str;
|
||||
|
||||
tree = cJSON_CreateObject();
|
||||
if(tree == NULL) return;
|
||||
|
||||
if(dynsec__general_config_save(tree)
|
||||
|| dynsec_clients__config_save(tree)
|
||||
|| dynsec_groups__config_save(tree)
|
||||
|| dynsec_roles__config_save(tree)){
|
||||
|
||||
cJSON_Delete(tree);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print json to string */
|
||||
json_str = cJSON_Print(tree);
|
||||
if(json_str == NULL){
|
||||
cJSON_Delete(tree);
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: Out of memory.\n");
|
||||
return;
|
||||
}
|
||||
cJSON_Delete(tree);
|
||||
json_str_len = strlen(json_str);
|
||||
|
||||
/* Save to file */
|
||||
file_path_len = strlen(g_config_file) + 1;
|
||||
file_path = mosquitto_malloc(file_path_len);
|
||||
if(file_path == NULL){
|
||||
mosquitto_free(json_str);
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: Out of memory.\n");
|
||||
return;
|
||||
}
|
||||
snprintf(file_path, file_path_len, "%s.new", g_config_file);
|
||||
|
||||
fptr = fopen(file_path, "wt");
|
||||
if(fptr == NULL){
|
||||
mosquitto_free(json_str);
|
||||
mosquitto_free(file_path);
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: File is not writable - check permissions.\n");
|
||||
return;
|
||||
}
|
||||
fwrite(json_str, 1, json_str_len, fptr);
|
||||
mosquitto_free(json_str);
|
||||
fclose(fptr);
|
||||
|
||||
/* Everything is ok, so move new file over proper file */
|
||||
if(rename(file_path, g_config_file) < 0){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error updating dynsec config file: %s", strerror(errno));
|
||||
}
|
||||
mosquitto_free(file_path);
|
||||
}
|
||||
@@ -132,6 +132,7 @@ struct dynsec__acl_default_access{
|
||||
|
||||
extern struct dynsec__group *dynsec_anonymous_group;
|
||||
extern struct dynsec__acl_default_access default_access;
|
||||
extern char *g_config_file;
|
||||
|
||||
/* ################################################################
|
||||
* #
|
||||
@@ -141,6 +142,7 @@ extern struct dynsec__acl_default_access default_access;
|
||||
|
||||
int dynsec__config_init(const char *filename);
|
||||
void dynsec__config_save(void);
|
||||
int dynsec__config_load(void);
|
||||
int dynsec__handle_control(cJSON *j_responses, struct mosquitto *context, cJSON *commands);
|
||||
void dynsec__command_reply(cJSON *j_responses, struct mosquitto *context, const char *command, const char *error, const char *correlation_data);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Contributors:
|
||||
MOSQUITTO_PLUGIN_DECLARE_VERSION(5);
|
||||
|
||||
static mosquitto_plugin_id_t *plg_id = NULL;
|
||||
static char *config_file = NULL;
|
||||
char *g_config_file = NULL;
|
||||
struct dynsec__acl_default_access default_access = {false, false, false, false};
|
||||
|
||||
void dynsec__command_reply(cJSON *j_responses, struct mosquitto *context, const char *command, const char *error, const char *correlation_data)
|
||||
@@ -276,199 +276,6 @@ internal_error:
|
||||
}
|
||||
|
||||
|
||||
static int dynsec__general_config_load(cJSON *tree)
|
||||
{
|
||||
cJSON *j_default_access, *jtmp;
|
||||
|
||||
j_default_access = cJSON_GetObjectItem(tree, "defaultACLAccess");
|
||||
if(j_default_access && cJSON_IsObject(j_default_access)){
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_PUB_C_SEND);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.publish_c_send = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.publish_c_send = false;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_PUB_C_RECV);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.publish_c_recv = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.publish_c_recv = false;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_SUB_GENERIC);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.subscribe = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.subscribe = false;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_UNSUB_GENERIC);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.unsubscribe = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.unsubscribe = false;
|
||||
}
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static int dynsec__general_config_save(cJSON *tree)
|
||||
{
|
||||
cJSON *j_default_access;
|
||||
|
||||
j_default_access = cJSON_CreateObject();
|
||||
if(j_default_access == NULL){
|
||||
return 1;
|
||||
}
|
||||
cJSON_AddItemToObject(tree, "defaultACLAccess", j_default_access);
|
||||
|
||||
if(cJSON_AddBoolToObject(j_default_access, ACL_TYPE_PUB_C_SEND, default_access.publish_c_send) == NULL
|
||||
|| cJSON_AddBoolToObject(j_default_access, ACL_TYPE_PUB_C_RECV, default_access.publish_c_recv) == NULL
|
||||
|| cJSON_AddBoolToObject(j_default_access, ACL_TYPE_SUB_GENERIC, default_access.subscribe) == NULL
|
||||
|| cJSON_AddBoolToObject(j_default_access, ACL_TYPE_UNSUB_GENERIC, default_access.unsubscribe) == NULL
|
||||
){
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static int dynsec__config_load(void)
|
||||
{
|
||||
FILE *fptr;
|
||||
long flen_l;
|
||||
size_t flen;
|
||||
char *json_str;
|
||||
cJSON *tree;
|
||||
|
||||
/* Load from file */
|
||||
fptr = fopen(config_file, "rb");
|
||||
if(fptr == NULL){
|
||||
/* Attempt to initialise a new config file */
|
||||
if(dynsec__config_init(config_file) == MOSQ_ERR_SUCCESS){
|
||||
mosquitto_log_printf(MOSQ_LOG_INFO, "Dynamic security plugin config not found, generating a default config.");
|
||||
mosquitto_log_printf(MOSQ_LOG_INFO, " Generated passwords are at %s.pw", config_file);
|
||||
/* If it works, try to open the file again */
|
||||
fptr = fopen(config_file, "rb");
|
||||
}
|
||||
|
||||
if(fptr == NULL){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR,
|
||||
"Error loading Dynamic security plugin config: File is not readable - check permissions.");
|
||||
return MOSQ_ERR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
fseek(fptr, 0, SEEK_END);
|
||||
flen_l = ftell(fptr);
|
||||
if(flen_l < 0){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: %s", strerror(errno));
|
||||
fclose(fptr);
|
||||
return 1;
|
||||
}else if(flen_l == 0){
|
||||
fclose(fptr);
|
||||
return 0;
|
||||
}
|
||||
flen = (size_t)flen_l;
|
||||
fseek(fptr, 0, SEEK_SET);
|
||||
json_str = mosquitto_calloc(flen+1, sizeof(char));
|
||||
if(json_str == NULL){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory.");
|
||||
fclose(fptr);
|
||||
return 1;
|
||||
}
|
||||
if(fread(json_str, 1, flen, fptr) != flen){
|
||||
mosquitto_log_printf(MOSQ_LOG_WARNING, "Error loading Dynamic security plugin config: Unable to read file contents.\n");
|
||||
mosquitto_free(json_str);
|
||||
fclose(fptr);
|
||||
return 1;
|
||||
}
|
||||
fclose(fptr);
|
||||
|
||||
tree = cJSON_Parse(json_str);
|
||||
mosquitto_free(json_str);
|
||||
if(tree == NULL){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: File is not valid JSON.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(dynsec__general_config_load(tree)
|
||||
|| dynsec_roles__config_load(tree)
|
||||
|| dynsec_clients__config_load(tree)
|
||||
|| dynsec_groups__config_load(tree)
|
||||
){
|
||||
|
||||
cJSON_Delete(tree);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cJSON_Delete(tree);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void dynsec__config_save(void)
|
||||
{
|
||||
cJSON *tree;
|
||||
size_t file_path_len;
|
||||
char *file_path;
|
||||
FILE *fptr;
|
||||
size_t json_str_len;
|
||||
char *json_str;
|
||||
|
||||
tree = cJSON_CreateObject();
|
||||
if(tree == NULL) return;
|
||||
|
||||
if(dynsec__general_config_save(tree)
|
||||
|| dynsec_clients__config_save(tree)
|
||||
|| dynsec_groups__config_save(tree)
|
||||
|| dynsec_roles__config_save(tree)){
|
||||
|
||||
cJSON_Delete(tree);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print json to string */
|
||||
json_str = cJSON_Print(tree);
|
||||
if(json_str == NULL){
|
||||
cJSON_Delete(tree);
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: Out of memory.\n");
|
||||
return;
|
||||
}
|
||||
cJSON_Delete(tree);
|
||||
json_str_len = strlen(json_str);
|
||||
|
||||
/* Save to file */
|
||||
file_path_len = strlen(config_file) + 1;
|
||||
file_path = mosquitto_malloc(file_path_len);
|
||||
if(file_path == NULL){
|
||||
mosquitto_free(json_str);
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: Out of memory.\n");
|
||||
return;
|
||||
}
|
||||
snprintf(file_path, file_path_len, "%s.new", config_file);
|
||||
|
||||
fptr = fopen(file_path, "wt");
|
||||
if(fptr == NULL){
|
||||
mosquitto_free(json_str);
|
||||
mosquitto_free(file_path);
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: File is not writable - check permissions.\n");
|
||||
return;
|
||||
}
|
||||
fwrite(json_str, 1, json_str_len, fptr);
|
||||
mosquitto_free(json_str);
|
||||
fclose(fptr);
|
||||
|
||||
/* Everything is ok, so move new file over proper file */
|
||||
if(rename(file_path, config_file) < 0){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error updating dynsec config file: %s", strerror(errno));
|
||||
}
|
||||
mosquitto_free(file_path);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *options, int option_count)
|
||||
{
|
||||
int i;
|
||||
@@ -477,14 +284,14 @@ int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, s
|
||||
|
||||
for(i=0; i<option_count; i++){
|
||||
if(!strcasecmp(options[i].key, "config_file")){
|
||||
config_file = mosquitto_strdup(options[i].value);
|
||||
if(config_file == NULL){
|
||||
g_config_file = mosquitto_strdup(options[i].value);
|
||||
if(g_config_file == NULL){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(config_file == NULL){
|
||||
if(g_config_file == NULL){
|
||||
mosquitto_log_printf(MOSQ_LOG_WARNING, "Warning: Dynamic security plugin has no plugin_opt_config_file defined. The plugin will not be activated.");
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
@@ -510,8 +317,8 @@ int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *options, int
|
||||
dynsec_clients__cleanup();
|
||||
dynsec_roles__cleanup();
|
||||
|
||||
mosquitto_free(config_file);
|
||||
config_file = NULL;
|
||||
mosquitto_free(g_config_file);
|
||||
g_config_file = NULL;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user