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