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