/src/mosquitto/plugins/dynamic-security/config.c
Line | Count | Source |
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 "dynamic_security.h" |
29 | | #include "json_help.h" |
30 | | |
31 | | |
32 | | static int dynsec__general_config_load(struct dynsec__data *data, cJSON *tree) |
33 | 5.58k | { |
34 | 5.58k | cJSON *j_default_access; |
35 | | |
36 | 5.58k | json_get_int64(tree, "changeIndex", &data->changeindex, true, 0); |
37 | | |
38 | 5.58k | j_default_access = cJSON_GetObjectItem(tree, "defaultACLAccess"); |
39 | 5.58k | if(j_default_access && cJSON_IsObject(j_default_access)){ |
40 | 30 | json_get_bool(j_default_access, ACL_TYPE_PUB_C_SEND, &data->default_access.publish_c_send, true, false); |
41 | 30 | json_get_bool(j_default_access, ACL_TYPE_PUB_C_RECV, &data->default_access.publish_c_recv, true, false); |
42 | 30 | json_get_bool(j_default_access, ACL_TYPE_SUB_GENERIC, &data->default_access.subscribe, true, false); |
43 | 30 | json_get_bool(j_default_access, ACL_TYPE_UNSUB_GENERIC, &data->default_access.unsubscribe, true, false); |
44 | 30 | } |
45 | 5.58k | return MOSQ_ERR_SUCCESS; |
46 | 5.58k | } |
47 | | |
48 | | |
49 | | static int dynsec__general_config_save(struct dynsec__data *data, cJSON *tree) |
50 | 0 | { |
51 | 0 | cJSON *j_default_access; |
52 | |
|
53 | 0 | cJSON_AddIntToObject(tree, "changeIndex", data->changeindex); |
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 | | |
74 | | int dynsec__config_from_json(struct dynsec__data *data, const char *json_str) |
75 | 5.70k | { |
76 | 5.70k | cJSON *tree; |
77 | | |
78 | 5.70k | tree = cJSON_Parse(json_str); |
79 | 5.70k | if(tree == NULL){ |
80 | 125 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: File is not valid JSON."); |
81 | 125 | return 1; |
82 | 125 | } |
83 | | |
84 | 5.58k | if(dynsec__general_config_load(data, tree) |
85 | 5.58k | || dynsec_roles__config_load(data, tree) |
86 | 5.57k | || dynsec_clients__config_load(data, tree) |
87 | 5.57k | || dynsec_groups__config_load(data, tree) |
88 | 5.58k | ){ |
89 | | |
90 | 3 | cJSON_Delete(tree); |
91 | 3 | return 1; |
92 | 3 | } |
93 | | |
94 | 5.57k | cJSON_Delete(tree); |
95 | 5.57k | return 0; |
96 | 5.58k | } |
97 | | |
98 | | |
99 | | int dynsec__config_load(struct dynsec__data *data) |
100 | 5.70k | { |
101 | 5.70k | FILE *fptr; |
102 | 5.70k | long flen_l; |
103 | 5.70k | size_t flen; |
104 | 5.70k | char *json_str; |
105 | 5.70k | int rc; |
106 | | |
107 | | /* Load from file */ |
108 | 5.70k | fptr = fopen(data->config_file, "rb"); |
109 | 5.70k | if(fptr == NULL){ |
110 | | /* Attempt to initialise a new config file */ |
111 | 0 | if(dynsec__config_init(data) == MOSQ_ERR_SUCCESS){ |
112 | | /* If it works, try to open the file again */ |
113 | 0 | fptr = fopen(data->config_file, "rb"); |
114 | 0 | } |
115 | |
|
116 | 0 | if(fptr == NULL){ |
117 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, |
118 | 0 | "Error loading Dynamic security plugin config: File is not readable - check permissions."); |
119 | 0 | return MOSQ_ERR_UNKNOWN; |
120 | 0 | } |
121 | 0 | } |
122 | | |
123 | 5.70k | fseek(fptr, 0, SEEK_END); |
124 | 5.70k | flen_l = ftell(fptr); |
125 | 5.70k | if(flen_l < 0){ |
126 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: %s", strerror(errno)); |
127 | 0 | fclose(fptr); |
128 | 0 | return 1; |
129 | 5.70k | }else if(flen_l == 0){ |
130 | 0 | fclose(fptr); |
131 | 0 | return 0; |
132 | 0 | } |
133 | 5.70k | flen = (size_t)flen_l; |
134 | 5.70k | fseek(fptr, 0, SEEK_SET); |
135 | 5.70k | json_str = mosquitto_calloc(flen+1, sizeof(char)); |
136 | 5.70k | if(json_str == NULL){ |
137 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory."); |
138 | 0 | fclose(fptr); |
139 | 0 | return 1; |
140 | 0 | } |
141 | 5.70k | if(fread(json_str, 1, flen, fptr) != flen){ |
142 | 0 | mosquitto_log_printf(MOSQ_LOG_WARNING, "Error loading Dynamic security plugin config: Unable to read file contents.\n"); |
143 | 0 | mosquitto_free(json_str); |
144 | 0 | fclose(fptr); |
145 | 0 | return 1; |
146 | 0 | } |
147 | 5.70k | fclose(fptr); |
148 | | |
149 | 5.70k | rc = dynsec__config_from_json(data, json_str); |
150 | 5.70k | free(json_str); |
151 | 5.70k | return rc; |
152 | 5.70k | } |
153 | | |
154 | | |
155 | | char *dynsec__config_to_json(struct dynsec__data *data) |
156 | 0 | { |
157 | 0 | cJSON *tree; |
158 | 0 | char *json_str; |
159 | |
|
160 | 0 | tree = cJSON_CreateObject(); |
161 | 0 | if(tree == NULL){ |
162 | 0 | return NULL; |
163 | 0 | } |
164 | | |
165 | 0 | if(dynsec__general_config_save(data, tree) |
166 | 0 | || dynsec_clients__config_save(data, tree) |
167 | 0 | || dynsec_groups__config_save(data, tree) |
168 | 0 | || dynsec_roles__config_save(data, tree)){ |
169 | |
|
170 | 0 | cJSON_Delete(tree); |
171 | 0 | return NULL; |
172 | 0 | } |
173 | | |
174 | | /* Print json to string */ |
175 | 0 | json_str = cJSON_Print(tree); |
176 | 0 | cJSON_Delete(tree); |
177 | 0 | return json_str; |
178 | 0 | } |
179 | | |
180 | | |
181 | | void dynsec__log_write_error(const char *msg) |
182 | 0 | { |
183 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: %s", msg); |
184 | 0 | } |
185 | | |
186 | | |
187 | | int dynsec__write_json_config(FILE *fptr, void *user_data) |
188 | 0 | { |
189 | 0 | struct dynsec__data *data = (struct dynsec__data *)user_data; |
190 | 0 | char *json_str; |
191 | 0 | size_t json_str_len; |
192 | 0 | int rc = MOSQ_ERR_SUCCESS; |
193 | |
|
194 | 0 | json_str = dynsec__config_to_json(data); |
195 | 0 | if(json_str == NULL){ |
196 | 0 | mosquitto_log_printf(MOSQ_LOG_ERR, "Error saving Dynamic security plugin config: Out of memory.\n"); |
197 | 0 | return MOSQ_ERR_NOMEM; |
198 | 0 | } |
199 | 0 | json_str_len = strlen(json_str); |
200 | |
|
201 | 0 | if(fwrite(json_str, 1, json_str_len, fptr) != json_str_len){ |
202 | 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); |
203 | 0 | rc = MOSQ_ERR_UNKNOWN; |
204 | 0 | } |
205 | |
|
206 | 0 | mosquitto_free(json_str); |
207 | 0 | return rc; |
208 | 0 | } |
209 | | |
210 | | |
211 | | void dynsec__config_batch_save(struct dynsec__data *data) |
212 | 0 | { |
213 | 0 | data->changeindex++; |
214 | 0 | data->need_save = true; |
215 | 0 | } |
216 | | |
217 | | |
218 | | void dynsec__config_save(struct dynsec__data *data) |
219 | 0 | { |
220 | 0 | data->need_save = false; |
221 | | mosquitto_write_file(data->config_file, true, &dynsec__write_json_config, data, &dynsec__log_write_error); |
222 | 0 | } |