Coverage Report

Created: 2025-09-04 06:10

/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
}