1 #ifndef DYNAMIC_SECURITY_H
2 #define DYNAMIC_SECURITY_H
3 /*
4 Copyright (c) 2020 Roger Light <roger@atchoo.org>
5 
6 All rights reserved. This program and the accompanying materials
7 are made available under the terms of the Eclipse Public License 2.0
8 and Eclipse Distribution License v1.0 which accompany this distribution.
9 
10 The Eclipse Public License is available at
11    https://www.eclipse.org/legal/epl-2.0/
12 and the Eclipse Distribution License is available at
13   http://www.eclipse.org/org/documents/edl-v10.php.
14 
15 SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
16 
17 Contributors:
18    Roger Light - initial implementation and documentation.
19 */
20 
21 #include <cjson/cJSON.h>
22 #include <uthash.h>
23 #include "mosquitto.h"
24 #include "password_mosq.h"
25 
26 /* ################################################################
27  * #
28  * # ACL types
29  * #
30  * ################################################################ */
31 
32 #define ACL_TYPE_PUB_C_RECV "publishClientReceive"
33 #define ACL_TYPE_PUB_C_SEND "publishClientSend"
34 #define ACL_TYPE_SUB_GENERIC "subscribe"
35 #define ACL_TYPE_SUB_LITERAL "subscribeLiteral"
36 #define ACL_TYPE_SUB_PATTERN "subscribePattern"
37 #define ACL_TYPE_UNSUB_GENERIC "unsubscribe"
38 #define ACL_TYPE_UNSUB_LITERAL "unsubscribeLiteral"
39 #define ACL_TYPE_UNSUB_PATTERN "unsubscribePattern"
40 
41 /* ################################################################
42  * #
43  * # Error codes
44  * #
45  * ################################################################ */
46 
47 #define ERR_USER_NOT_FOUND 10000
48 #define ERR_GROUP_NOT_FOUND 10001
49 #define ERR_LIST_NOT_FOUND 10002
50 
51 /* ################################################################
52  * #
53  * # Datatypes
54  * #
55  * ################################################################ */
56 
57 struct dynsec__clientlist{
58 	UT_hash_handle hh;
59 	struct dynsec__client *client;
60 	int priority;
61 };
62 
63 struct dynsec__grouplist{
64 	UT_hash_handle hh;
65 	struct dynsec__group *group;
66 	int priority;
67 };
68 
69 struct dynsec__rolelist{
70 	UT_hash_handle hh;
71 	char *rolename;
72 	struct dynsec__role *role;
73 	int priority;
74 };
75 
76 struct dynsec__client{
77 	UT_hash_handle hh;
78 	struct mosquitto_pw pw;
79 	struct dynsec__rolelist *rolelist;
80 	struct dynsec__grouplist *grouplist;
81 	char *username;
82 	char *clientid;
83 	char *text_name;
84 	char *text_description;
85 	bool disabled;
86 };
87 
88 struct dynsec__group{
89 	UT_hash_handle hh;
90 	struct dynsec__rolelist *rolelist;
91 	struct dynsec__clientlist *clientlist;
92 	char *groupname;
93 	char *text_name;
94 	char *text_description;
95 };
96 
97 
98 struct dynsec__acl{
99 	UT_hash_handle hh;
100 	char *topic;
101 	int priority;
102 	bool allow;
103 };
104 
105 struct dynsec__acls{
106 	struct dynsec__acl *publish_c_send;
107 	struct dynsec__acl *publish_c_recv;
108 	struct dynsec__acl *subscribe_literal;
109 	struct dynsec__acl *subscribe_pattern;
110 	struct dynsec__acl *unsubscribe_literal;
111 	struct dynsec__acl *unsubscribe_pattern;
112 };
113 
114 struct dynsec__role{
115 	UT_hash_handle hh;
116 	struct dynsec__acls acls;
117 	struct dynsec__clientlist *clientlist;
118 	struct dynsec__grouplist *grouplist;
119 	char *rolename;
120 	char *text_name;
121 	char *text_description;
122 };
123 
124 struct dynsec__acl_default_access{
125 	bool publish_c_send;
126 	bool publish_c_recv;
127 	bool subscribe;
128 	bool unsubscribe;
129 };
130 
131 extern struct dynsec__group *dynsec_anonymous_group;
132 extern struct dynsec__acl_default_access default_access;
133 
134 /* ################################################################
135  * #
136  * # Plugin Functions
137  * #
138  * ################################################################ */
139 
140 void dynsec__config_save(void);
141 int dynsec__handle_control(cJSON *j_responses, struct mosquitto *context, cJSON *commands);
142 void dynsec__command_reply(cJSON *j_responses, struct mosquitto *context, const char *command, const char *error, const char *correlation_data);
143 
144 
145 /* ################################################################
146  * #
147  * # ACL Functions
148  * #
149  * ################################################################ */
150 
151 int dynsec__acl_check_callback(int event, void *event_data, void *userdata);
152 bool sub_acl_check(const char *acl, const char *sub);
153 
154 
155 /* ################################################################
156  * #
157  * # Auth Functions
158  * #
159  * ################################################################ */
160 
161 int dynsec_auth__base64_encode(unsigned char *in, int in_len, char **encoded);
162 int dynsec_auth__base64_decode(char *in, unsigned char **decoded, int *decoded_len);
163 int dynsec_auth__pw_hash(struct dynsec__client *client, const char *password, unsigned char *password_hash, int password_hash_len, bool new_password);
164 int dynsec_auth__basic_auth_callback(int event, void *event_data, void *userdata);
165 
166 
167 /* ################################################################
168  * #
169  * # Client Functions
170  * #
171  * ################################################################ */
172 
173 void dynsec_clients__cleanup(void);
174 int dynsec_clients__config_load(cJSON *tree);
175 int dynsec_clients__config_save(cJSON *tree);
176 int dynsec_clients__process_add_role(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
177 int dynsec_clients__process_create(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
178 int dynsec_clients__process_delete(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
179 int dynsec_clients__process_disable(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
180 int dynsec_clients__process_enable(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
181 int dynsec_clients__process_get(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
182 int dynsec_clients__process_list(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
183 int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
184 int dynsec_clients__process_remove_role(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
185 int dynsec_clients__process_set_id(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
186 int dynsec_clients__process_set_password(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
187 struct dynsec__client *dynsec_clients__find(const char *username);
188 
189 
190 /* ################################################################
191  * #
192  * # Client List Functions
193  * #
194  * ################################################################ */
195 
196 cJSON *dynsec_clientlist__all_to_json(struct dynsec__clientlist *base_clientlist);
197 int dynsec_clientlist__add(struct dynsec__clientlist **base_clientlist, struct dynsec__client *client, int priority);
198 void dynsec_clientlist__cleanup(struct dynsec__clientlist **base_clientlist);
199 void dynsec_clientlist__remove(struct dynsec__clientlist **base_clientlist, struct dynsec__client *client);
200 void dynsec_clientlist__kick_all(struct dynsec__clientlist *base_clientlist);
201 
202 
203 /* ################################################################
204  * #
205  * # Group Functions
206  * #
207  * ################################################################ */
208 
209 void dynsec_groups__cleanup(void);
210 int dynsec_groups__config_load(cJSON *tree);
211 int dynsec_groups__add_client(const char *username, const char *groupname, int priority, bool update_config);
212 int dynsec_groups__config_save(cJSON *tree);
213 int dynsec_groups__process_add_client(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
214 int dynsec_groups__process_add_role(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
215 int dynsec_groups__process_create(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
216 int dynsec_groups__process_delete(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
217 int dynsec_groups__process_get(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
218 int dynsec_groups__process_list(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
219 int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
220 int dynsec_groups__process_remove_client(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
221 int dynsec_groups__process_remove_role(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
222 int dynsec_groups__process_get_anonymous_group(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
223 int dynsec_groups__process_set_anonymous_group(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
224 int dynsec_groups__remove_client(const char *username, const char *groupname, bool update_config);
225 struct dynsec__group *dynsec_groups__find(const char *groupname);
226 
227 
228 /* ################################################################
229  * #
230  * # Group List Functions
231  * #
232  * ################################################################ */
233 
234 cJSON *dynsec_grouplist__all_to_json(struct dynsec__grouplist *base_grouplist);
235 int dynsec_grouplist__add(struct dynsec__grouplist **base_grouplist, struct dynsec__group *group, int priority);
236 void dynsec_grouplist__cleanup(struct dynsec__grouplist **base_grouplist);
237 void dynsec_grouplist__remove(struct dynsec__grouplist **base_grouplist, struct dynsec__group *group);
238 
239 
240 /* ################################################################
241  * #
242  * # Role Functions
243  * #
244  * ################################################################ */
245 
246 void dynsec_roles__cleanup(void);
247 int dynsec_roles__config_load(cJSON *tree);
248 int dynsec_roles__config_save(cJSON *tree);
249 int dynsec_roles__process_add_acl(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
250 int dynsec_roles__process_create(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
251 int dynsec_roles__process_delete(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
252 int dynsec_roles__process_get(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
253 int dynsec_roles__process_list(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
254 int dynsec_roles__process_modify(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
255 int dynsec_roles__process_remove_acl(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
256 struct dynsec__role *dynsec_roles__find(const char *rolename);
257 
258 
259 /* ################################################################
260  * #
261  * # Role List Functions
262  * #
263  * ################################################################ */
264 
265 int dynsec_rolelist__client_add(struct dynsec__client *client, struct dynsec__role *role, int priority);
266 int dynsec_rolelist__client_remove(struct dynsec__client *client, struct dynsec__role *role);
267 int dynsec_rolelist__group_add(struct dynsec__group *group, struct dynsec__role *role, int priority);
268 void dynsec_rolelist__group_remove(struct dynsec__group *group, struct dynsec__role *role);
269 int dynsec_rolelist__load_from_json(cJSON *command, struct dynsec__rolelist **rolelist);
270 void dynsec_rolelist__cleanup(struct dynsec__rolelist **base_rolelist);
271 cJSON *dynsec_rolelist__all_to_json(struct dynsec__rolelist *base_rolelist);
272 
273 #endif
274