/src/mosquitto/plugins/dynamic-security/rolelist.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 <stdio.h> |
23 | | #include <string.h> |
24 | | #include <uthash.h> |
25 | | #include <utlist.h> |
26 | | |
27 | | #include "dynamic_security.h" |
28 | | #include "json_help.h" |
29 | | |
30 | | |
31 | | /* ################################################################ |
32 | | * # |
33 | | * # Utility functions |
34 | | * # |
35 | | * ################################################################ */ |
36 | | |
37 | | |
38 | | static int rolelist_cmp(void *a, void *b) |
39 | 684k | { |
40 | 684k | int prio; |
41 | 684k | struct dynsec__rolelist *rolelist_a = a; |
42 | 684k | struct dynsec__rolelist *rolelist_b = b; |
43 | | |
44 | 684k | prio = rolelist_b->priority - rolelist_a->priority; |
45 | 684k | if(prio == 0){ |
46 | 683k | return strcmp(rolelist_a->rolename, rolelist_b->rolename); |
47 | 683k | }else{ |
48 | 1.03k | return prio; |
49 | 1.03k | } |
50 | 684k | } |
51 | | |
52 | | |
53 | | static void dynsec_rolelist__free_item(struct dynsec__rolelist **base_rolelist, struct dynsec__rolelist *rolelist) |
54 | 38.9k | { |
55 | 38.9k | HASH_DELETE(hh, *base_rolelist, rolelist); |
56 | 38.9k | mosquitto_free(rolelist); |
57 | 38.9k | } |
58 | | |
59 | | |
60 | | void dynsec_rolelist__cleanup(struct dynsec__rolelist **base_rolelist) |
61 | 70.7k | { |
62 | 70.7k | struct dynsec__rolelist *rolelist, *rolelist_tmp; |
63 | | |
64 | 70.7k | HASH_ITER(hh, *base_rolelist, rolelist, rolelist_tmp){ |
65 | 38.9k | dynsec_rolelist__free_item(base_rolelist, rolelist); |
66 | 38.9k | } |
67 | 70.7k | } |
68 | | |
69 | | |
70 | | static int dynsec_rolelist__remove_role(struct dynsec__rolelist **base_rolelist, const struct dynsec__role *role) |
71 | 0 | { |
72 | 0 | struct dynsec__rolelist *found_rolelist; |
73 | |
|
74 | 0 | HASH_FIND(hh, *base_rolelist, role->rolename, strlen(role->rolename), found_rolelist); |
75 | 0 | if(found_rolelist){ |
76 | 0 | dynsec_rolelist__free_item(base_rolelist, found_rolelist); |
77 | 0 | return MOSQ_ERR_SUCCESS; |
78 | 0 | }else{ |
79 | 0 | return MOSQ_ERR_NOT_FOUND; |
80 | 0 | } |
81 | 0 | } |
82 | | |
83 | | |
84 | | int dynsec_rolelist__client_remove(struct dynsec__client *client, struct dynsec__role *role) |
85 | 0 | { |
86 | 0 | int rc; |
87 | 0 | struct dynsec__clientlist *found_clientlist; |
88 | |
|
89 | 0 | rc = dynsec_rolelist__remove_role(&client->rolelist, role); |
90 | 0 | if(rc){ |
91 | 0 | return rc; |
92 | 0 | } |
93 | | |
94 | 0 | HASH_FIND(hh, role->clientlist, client->username, strlen(client->username), found_clientlist); |
95 | 0 | if(found_clientlist){ |
96 | 0 | HASH_DELETE(hh, role->clientlist, found_clientlist); |
97 | 0 | mosquitto_free(found_clientlist); |
98 | 0 | return MOSQ_ERR_SUCCESS; |
99 | 0 | }else{ |
100 | 0 | return MOSQ_ERR_NOT_FOUND; |
101 | 0 | } |
102 | 0 | } |
103 | | |
104 | | |
105 | | void dynsec_rolelist__group_remove(struct dynsec__group *group, struct dynsec__role *role) |
106 | 0 | { |
107 | 0 | dynsec_rolelist__remove_role(&group->rolelist, role); |
108 | 0 | dynsec_grouplist__remove(&role->grouplist, group); |
109 | 0 | } |
110 | | |
111 | | |
112 | | static int dynsec_rolelist__add(struct dynsec__rolelist **base_rolelist, struct dynsec__role *role, int priority) |
113 | 58.4k | { |
114 | 58.4k | struct dynsec__rolelist *rolelist; |
115 | 58.4k | size_t rolename_len; |
116 | | |
117 | 58.4k | if(role == NULL){ |
118 | 12.1k | return MOSQ_ERR_INVAL; |
119 | 12.1k | } |
120 | 46.2k | rolename_len = strlen(role->rolename); |
121 | 46.2k | if(rolename_len == 0){ |
122 | 0 | return MOSQ_ERR_INVAL; |
123 | 0 | } |
124 | | |
125 | 46.2k | HASH_FIND(hh, *base_rolelist, role->rolename, rolename_len, rolelist); |
126 | 46.2k | if(rolelist){ |
127 | 7.35k | return MOSQ_ERR_ALREADY_EXISTS; |
128 | 38.9k | }else{ |
129 | 38.9k | rolelist = mosquitto_calloc(1, sizeof(struct dynsec__rolelist) + rolename_len + 1); |
130 | 38.9k | if(rolelist == NULL){ |
131 | 0 | return MOSQ_ERR_NOMEM; |
132 | 0 | } |
133 | | |
134 | 38.9k | rolelist->role = role; |
135 | 38.9k | rolelist->priority = priority; |
136 | 38.9k | strncpy(rolelist->rolename, role->rolename, rolename_len+1); |
137 | 38.9k | HASH_ADD_INORDER(hh, *base_rolelist, rolename, rolename_len, rolelist, rolelist_cmp); |
138 | 38.9k | return MOSQ_ERR_SUCCESS; |
139 | 38.9k | } |
140 | 46.2k | } |
141 | | |
142 | | |
143 | | int dynsec_rolelist__client_add(struct dynsec__client *client, struct dynsec__role *role, int priority) |
144 | 42.1k | { |
145 | 42.1k | struct dynsec__rolelist *rolelist; |
146 | 42.1k | int rc; |
147 | | |
148 | 42.1k | rc = dynsec_rolelist__add(&client->rolelist, role, priority); |
149 | 42.1k | if(rc){ |
150 | 15.2k | return rc; |
151 | 15.2k | } |
152 | | |
153 | 26.8k | HASH_FIND(hh, client->rolelist, role->rolename, strlen(role->rolename), rolelist); |
154 | 26.8k | if(rolelist == NULL){ |
155 | | /* This should never happen because the above add_role succeeded. */ |
156 | 0 | return MOSQ_ERR_UNKNOWN; |
157 | 0 | } |
158 | | |
159 | 26.8k | rc = dynsec_clientlist__add(&role->clientlist, client, priority); |
160 | 26.8k | if(rc){ |
161 | 0 | dynsec_rolelist__remove_role(&client->rolelist, role); |
162 | 0 | } |
163 | | |
164 | 26.8k | return rc; |
165 | 26.8k | } |
166 | | |
167 | | |
168 | | int dynsec_rolelist__group_add(struct dynsec__group *group, struct dynsec__role *role, int priority) |
169 | 16.2k | { |
170 | 16.2k | int rc; |
171 | | |
172 | 16.2k | rc = dynsec_rolelist__add(&group->rolelist, role, priority); |
173 | 16.2k | if(rc){ |
174 | 4.25k | return rc; |
175 | 4.25k | } |
176 | | |
177 | 12.0k | rc = dynsec_grouplist__add(&role->grouplist, group, priority); |
178 | 12.0k | if(rc){ |
179 | 0 | dynsec_rolelist__remove_role(&group->rolelist, role); |
180 | 0 | } |
181 | 12.0k | return rc; |
182 | 16.2k | } |
183 | | |
184 | | |
185 | | int dynsec_rolelist__load_from_json(struct dynsec__data *data, cJSON *command, struct dynsec__rolelist **rolelist) |
186 | 0 | { |
187 | 0 | cJSON *j_roles, *j_role; |
188 | 0 | int priority; |
189 | 0 | struct dynsec__role *role; |
190 | 0 | const char *rolename; |
191 | |
|
192 | 0 | j_roles = cJSON_GetObjectItem(command, "roles"); |
193 | 0 | if(j_roles){ |
194 | 0 | if(cJSON_IsArray(j_roles)){ |
195 | 0 | cJSON_ArrayForEach(j_role, j_roles){ |
196 | 0 | if(json_get_string(j_role, "rolename", &rolename, false) == MOSQ_ERR_SUCCESS){ |
197 | 0 | json_get_int(j_role, "priority", &priority, true, -1); |
198 | 0 | if(priority > PRIORITY_MAX){ |
199 | 0 | priority = PRIORITY_MAX; |
200 | 0 | } |
201 | 0 | role = dynsec_roles__find(data, rolename); |
202 | 0 | if(role){ |
203 | 0 | dynsec_rolelist__add(rolelist, role, priority); |
204 | 0 | }else{ |
205 | 0 | dynsec_rolelist__cleanup(rolelist); |
206 | 0 | return MOSQ_ERR_NOT_FOUND; |
207 | 0 | } |
208 | 0 | }else{ |
209 | 0 | return MOSQ_ERR_INVAL; |
210 | 0 | } |
211 | 0 | } |
212 | 0 | return MOSQ_ERR_SUCCESS; |
213 | 0 | }else{ |
214 | 0 | return MOSQ_ERR_INVAL; |
215 | 0 | } |
216 | 0 | }else{ |
217 | 0 | return ERR_LIST_NOT_FOUND; |
218 | 0 | } |
219 | 0 | } |
220 | | |
221 | | |
222 | | cJSON *dynsec_rolelist__all_to_json(struct dynsec__rolelist *base_rolelist) |
223 | 0 | { |
224 | 0 | struct dynsec__rolelist *rolelist, *rolelist_tmp; |
225 | 0 | cJSON *j_roles, *j_role; |
226 | |
|
227 | 0 | j_roles = cJSON_CreateArray(); |
228 | 0 | if(j_roles == NULL){ |
229 | 0 | return NULL; |
230 | 0 | } |
231 | | |
232 | 0 | HASH_ITER(hh, base_rolelist, rolelist, rolelist_tmp){ |
233 | 0 | j_role = cJSON_CreateObject(); |
234 | 0 | if(j_role == NULL){ |
235 | 0 | cJSON_Delete(j_roles); |
236 | 0 | return NULL; |
237 | 0 | } |
238 | 0 | cJSON_AddItemToArray(j_roles, j_role); |
239 | |
|
240 | 0 | if(cJSON_AddStringToObject(j_role, "rolename", rolelist->role->rolename) == NULL |
241 | 0 | || (rolelist->priority != -1 && cJSON_AddIntToObject(j_role, "priority", rolelist->priority) == NULL) |
242 | 0 | ){ |
243 | |
|
244 | 0 | cJSON_Delete(j_roles); |
245 | 0 | return NULL; |
246 | 0 | } |
247 | 0 | } |
248 | 0 | return j_roles; |
249 | 0 | } |