/src/mosquitto/plugins/dynamic-security/config.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright (c) 2020-2021 Roger Light <roger@atchoo.org> |
3 | | |
4 | | All rights reserved. This program and the accompanying materials |
5 | | are made available under the terms of the Eclipse Public License 2.0 |
6 | | and Eclipse Distribution License v1.0 which accompany this distribution. |
7 | | |
8 | | The Eclipse Public License is available at |
9 | | https://www.eclipse.org/legal/epl-2.0/ |
10 | | and the Eclipse Distribution License is available at |
11 | | http://www.eclipse.org/org/documents/edl-v10.php. |
12 | | |
13 | | SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
14 | | |
15 | | Contributors: |
16 | | Roger Light - initial implementation and documentation. |
17 | | */ |
18 | | |
19 | | #include "config.h" |
20 | | |
21 | | #include <cjson/cJSON.h> |
22 | | #include <errno.h> |
23 | | #include <stdio.h> |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | #include <sys/stat.h> |
27 | | |
28 | | #include "json_help.h" |
29 | | #include "misc_mosq.h" |
30 | | #include "mosquitto.h" |
31 | | #include "mosquitto_broker.h" |
32 | | #include "mosquitto_plugin.h" |
33 | | #include "mqtt_protocol.h" |
34 | | |
35 | | #include "dynamic_security.h" |
36 | | |
37 | | static int dynsec__general_config_load(struct dynsec__data *data, cJSON *tree) |
38 | 4.42k | { |
39 | 4.42k | cJSON *j_default_access; |
40 | | |
41 | 4.42k | j_default_access = cJSON_GetObjectItem(tree, "defaultACLAccess"); |
42 | 4.42k | if(j_default_access && cJSON_IsObject(j_default_access)){ |
43 | 133 | json_get_bool(j_default_access, ACL_TYPE_PUB_C_SEND, &data->default_access.publish_c_send, true, false); |
44 | 133 | json_get_bool(j_default_access, ACL_TYPE_PUB_C_RECV, &data->default_access.publish_c_recv, true, false); |
45 | 133 | json_get_bool(j_default_access, ACL_TYPE_SUB_GENERIC, &data->default_access.subscribe, true, false); |
46 | 133 | json_get_bool(j_default_access, ACL_TYPE_UNSUB_GENERIC, &data->default_access.unsubscribe, true, false); |
47 | 133 | } |
48 | 4.42k | return MOSQ_ERR_SUCCESS; |
49 | 4.42k | } |
50 | | |
51 | | static int dynsec__general_config_save(struct dynsec__data *data, cJSON *tree) |
52 | 0 | { |
53 | 0 | cJSON *j_default_access; |
54 | |
|
55 | 0 | j_default_access = cJSON_CreateObject(); |
56 | 0 | if(j_default_access == NULL){ |
57 | 0 | return 1; |
58 | 0 | } |
59 | 0 | cJSON_AddItemToObject(tree, "defaultACLAccess", j_default_access); |
60 | |
|
61 | 0 | if(cJSON_AddBoolToObject(j_default_access, ACL_TYPE_PUB_C_SEND, data->default_access.publish_c_send) == NULL |
62 | 0 | || cJSON_AddBoolToObject(j_default_access, ACL_TYPE_PUB_C_RECV, data->default_access.publish_c_recv) == NULL |
63 | 0 | || cJSON_AddBoolToObject(j_default_access, ACL_TYPE_SUB_GENERIC, data->default_access.subscribe) == NULL |
64 | 0 | || cJSON_AddBoolToObject(j_default_access, ACL_TYPE_UNSUB_GENERIC, data->default_access.unsubscribe) == NULL |
65 | 0 | ){ |
66 | |
|
67 | 0 | return 1; |
68 | 0 | } |
69 | | |
70 | 0 | return MOSQ_ERR_SUCCESS; |
71 | 0 | } |
72 | | |
73 | | int dynsec__config_from_json(struct dynsec__data *data, const char *json_str) |
74 | 4.56k | { |
75 | 4.56k | cJSON *tree; |
76 | | |
77 | 4.56k | tree = cJSON_Parse(json_str); |
78 | 4.56k | if(tree == NULL){ |
79 | 140 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: File is not valid JSON."); |
80 | 140 | return 1; |
81 | 140 | } |
82 | | |
83 | 4.42k | if(dynsec__general_config_load(data, tree) |
84 | 4.42k | || dynsec_roles__config_load(data, tree) |
85 | 4.42k | || dynsec_clients__config_load(data, tree) |
86 | 4.42k | || dynsec_groups__config_load(data, tree) |
87 | 4.42k | ){ |
88 | | |
89 | 3 | cJSON_Delete(tree); |
90 | 3 | return 1; |
91 | 3 | } |
92 | | |
93 | 4.41k | cJSON_Delete(tree); |
94 | 4.41k | return 0; |
95 | 4.42k | } |
96 | | |
97 | | int dynsec__config_load(struct dynsec__data *data) |
98 | 4.56k | { |
99 | 4.56k | FILE *fptr; |
100 | 4.56k | long flen_l; |
101 | 4.56k | size_t flen; |
102 | 4.56k | char *json_str; |
103 | 4.56k | int rc; |
104 | | |
105 | | /* Load from file */ |
106 | 4.56k | fptr = fopen(data->config_file, "rb"); |
107 | 4.56k | if(fptr == NULL){ |
108 | | /* Attempt to initialise a new config file */ |
109 | 0 | if(dynsec__config_init(data) == MOSQ_ERR_SUCCESS){ |
110 | | /* If it works, try to open the file again */ |
111 | 0 | fptr = fopen(data->config_file, "rb"); |
112 | 0 | } |
113 | |
|
114 | 0 | if(fptr == NULL){ |
115 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, |
116 | 0 | "Error loading Dynamic security plugin config: File is not readable - check permissions."); |
117 | 0 | return MOSQ_ERR_UNKNOWN; |
118 | 0 | } |
119 | 0 | } |
120 | | |
121 | 4.56k | fseek(fptr, 0, SEEK_END); |
122 | 4.56k | flen_l = ftell(fptr); |
123 | 4.56k | if(flen_l < 0){ |
124 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: %s", strerror(errno)); |
125 | 0 | fclose(fptr); |
126 | 0 | return 1; |
127 | 4.56k | }else if(flen_l == 0){ |
128 | 0 | fclose(fptr); |
129 | 0 | return 0; |
130 | 0 | } |
131 | 4.56k | flen = (size_t)flen_l; |
132 | 4.56k | fseek(fptr, 0, SEEK_SET); |
133 | 4.56k | json_str = mosquitto_calloc(flen+1, sizeof(char)); |
134 | 4.56k | if(json_str == NULL){ |
135 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory."); |
136 | 0 | fclose(fptr); |
137 | 0 | return 1; |
138 | 0 | } |
139 | 4.56k | if(fread(json_str, 1, flen, fptr) != flen){ |
140 | 0 | mosquitto_log_printf(MOSQ_LOG_WARNING, "Error loading Dynamic security plugin config: Unable to read file contents.\n"); |
141 | 0 | mosquitto_free(json_str); |
142 | 0 | fclose(fptr); |
143 | 0 | return 1; |
144 | 0 | } |
145 | 4.56k | fclose(fptr); |
146 | | |
147 | 4.56k | rc = dynsec__config_from_json(data, json_str); |
148 | 4.56k | free(json_str); |
149 | 4.56k | return rc; |
150 | 4.56k | } |
151 | | |
152 | | char *dynsec__config_to_json(struct dynsec__data *data) |
153 | 0 | { |
154 | 0 | cJSON *tree; |
155 | 0 | char *json_str; |
156 | |
|
157 | 0 | tree = cJSON_CreateObject(); |
158 | 0 | if(tree == NULL) return NULL; |
159 | | |
160 | 0 | if(dynsec__general_config_save(data, tree) |
161 | 0 | || dynsec_clients__config_save(data, tree) |
162 | 0 | || dynsec_groups__config_save(data, tree) |
163 | 0 | || dynsec_roles__config_save(data, tree)){ |
164 | |
|
165 | 0 | cJSON_Delete(tree); |
166 | 0 | return NULL; |
167 | 0 | } |
168 | | |
169 | | /* Print json to string */ |
170 | 0 | json_str = cJSON_Print(tree); |
171 | 0 | cJSON_Delete(tree); |
172 | 0 | return json_str; |
173 | 0 | } |
174 | | |
175 | | void dynsec__log_write_error(const char* msg) |
176 | 0 | { |
177 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: %s", msg); |
178 | 0 | } |
179 | | |
180 | | int dynsec__write_json_config(FILE* fptr, void* user_data) |
181 | 0 | { |
182 | 0 | struct dynsec__data *data = (struct dynsec__data *)user_data; |
183 | 0 | char *json_str; |
184 | 0 | size_t json_str_len; |
185 | 0 | int rc = MOSQ_ERR_SUCCESS; |
186 | |
|
187 | 0 | json_str = dynsec__config_to_json(data); |
188 | 0 | if(json_str == NULL){ |
189 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: Out of memory.\n"); |
190 | 0 | return MOSQ_ERR_NOMEM; |
191 | 0 | } |
192 | 0 | json_str_len = strlen(json_str); |
193 | |
|
194 | 0 | if (fwrite(json_str, 1, json_str_len, fptr) != json_str_len){ |
195 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: Cannot write whole config (%ld) bytes to file %s", json_str_len, data->config_file); |
196 | 0 | rc = MOSQ_ERR_UNKNOWN; |
197 | 0 | } |
198 | |
|
199 | 0 | mosquitto_free(json_str); |
200 | 0 | return rc; |
201 | 0 | } |
202 | | |
203 | | void dynsec__config_batch_save(struct dynsec__data *data) |
204 | 0 | { |
205 | 0 | data->need_save = true; |
206 | 0 | } |
207 | | |
208 | | void dynsec__config_save(struct dynsec__data *data) |
209 | 0 | { |
210 | 0 | data->need_save = false; |
211 | 0 | mosquitto_write_file(data->config_file, true, &dynsec__write_json_config, data, &dynsec__log_write_error); |
212 | 0 | } |