mirror of
https://github.com/eclipse-mosquitto/mosquitto.git
synced 2026-05-18 12:44:18 +02:00
dynsec: Fix potential grouplist leaks.
This commit is contained in:
parent
04d53e8919
commit
fe436cda95
|
|
@ -20,6 +20,7 @@ add_library(mosquitto_dynamic_security SHARED
|
|||
clientlist.c
|
||||
dynamic_security.h
|
||||
groups.c
|
||||
grouplist.c
|
||||
json_help.c
|
||||
json_help.h
|
||||
plugin.c
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ OBJS= \
|
|||
clients.o \
|
||||
clientlist.o \
|
||||
groups.o \
|
||||
grouplist.o \
|
||||
json_help.o \
|
||||
plugin.o \
|
||||
roles.o \
|
||||
|
|
@ -37,6 +38,9 @@ clientlist.o : clientlist.c dynamic_security.h
|
|||
groups.o : groups.c dynamic_security.h
|
||||
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) -c $< -o $@
|
||||
|
||||
grouplist.o : grouplist.c dynamic_security.h
|
||||
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) -c $< -o $@
|
||||
|
||||
json_help.o : json_help.c dynamic_security.h
|
||||
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) -c $< -o $@
|
||||
|
||||
|
|
|
|||
|
|
@ -778,7 +778,7 @@ static int dynsec__remove_client_from_all_groups(const char *username)
|
|||
client = dynsec_clients__find(username);
|
||||
if(client){
|
||||
HASH_ITER(hh, client->grouplist, grouplist, grouplist_tmp){
|
||||
dynsec_groups__remove_client(username, grouplist->groupname, false);
|
||||
dynsec_groups__remove_client(username, grouplist->group->groupname, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -814,7 +814,7 @@ static cJSON *add_client_to_json(struct dynsec__client *client, bool verbose)
|
|||
}
|
||||
cJSON_AddItemToObject(j_client, "roles", j_roles);
|
||||
|
||||
j_groups = dynsec_grouplists__all_to_json(client->grouplist);
|
||||
j_groups = dynsec_grouplist__all_to_json(client->grouplist);
|
||||
if(j_groups == NULL){
|
||||
cJSON_Delete(j_client);
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ struct dynsec__clientlist{
|
|||
|
||||
struct dynsec__grouplist{
|
||||
UT_hash_handle hh;
|
||||
char *groupname;
|
||||
struct dynsec__group *group;
|
||||
int priority;
|
||||
};
|
||||
|
|
@ -223,8 +222,18 @@ int dynsec_groups__process_set_anonymous_group(cJSON *j_responses, struct mosqui
|
|||
int dynsec_groups__remove_client(const char *username, const char *groupname, bool update_config);
|
||||
struct dynsec__group *dynsec_groups__find(const char *groupname);
|
||||
|
||||
cJSON *dynsec_grouplists__all_to_json(struct dynsec__grouplist *base_grouplist);
|
||||
int dynsec_grouplist__cmp(void *a, void *b);
|
||||
|
||||
/* ################################################################
|
||||
* #
|
||||
* # Group List Functions
|
||||
* #
|
||||
* ################################################################ */
|
||||
|
||||
cJSON *dynsec_grouplist__all_to_json(struct dynsec__grouplist *base_grouplist);
|
||||
int dynsec_grouplist__add(struct dynsec__grouplist **base_grouplist, struct dynsec__group *group, int priority);
|
||||
void dynsec_grouplist__cleanup(struct dynsec__grouplist **base_grouplist);
|
||||
void dynsec_grouplist__remove(struct dynsec__grouplist **base_grouplist, struct dynsec__group *group);
|
||||
|
||||
|
||||
/* ################################################################
|
||||
* #
|
||||
|
|
@ -247,7 +256,7 @@ struct dynsec__role *dynsec_roles__find(const char *rolename);
|
|||
int dynsec_rolelists__client_add_role(struct dynsec__client *client, struct dynsec__role *role, int priority);
|
||||
int dynsec_rolelists__client_remove_role(struct dynsec__client *client, struct dynsec__role *role);
|
||||
int dynsec_rolelists__group_add_role(struct dynsec__group *group, struct dynsec__role *role, int priority);
|
||||
int dynsec_rolelists__group_remove_role(struct dynsec__group *group, struct dynsec__role *role);
|
||||
void dynsec_rolelists__group_remove_role(struct dynsec__group *group, struct dynsec__role *role);
|
||||
int dynsec_rolelists__load_from_json(cJSON *command, struct dynsec__rolelist **rolelist);
|
||||
void dynsec_rolelists__free_all(struct dynsec__rolelist **base_rolelist);
|
||||
cJSON *dynsec_rolelists__all_to_json(struct dynsec__rolelist *base_rolelist);
|
||||
|
|
|
|||
139
plugins/dynamic-security/grouplist.c
Normal file
139
plugins/dynamic-security/grouplist.c
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
Copyright (c) 2020 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cJSON.h>
|
||||
#include <stdio.h>
|
||||
#include <uthash.h>
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "mosquitto_broker.h"
|
||||
#include "json_help.h"
|
||||
|
||||
#include "dynamic_security.h"
|
||||
|
||||
/* ################################################################
|
||||
* #
|
||||
* # Plugin global variables
|
||||
* #
|
||||
* ################################################################ */
|
||||
|
||||
/* ################################################################
|
||||
* #
|
||||
* # Function declarations
|
||||
* #
|
||||
* ################################################################ */
|
||||
|
||||
/* ################################################################
|
||||
* #
|
||||
* # Local variables
|
||||
* #
|
||||
* ################################################################ */
|
||||
|
||||
/* ################################################################
|
||||
* #
|
||||
* # Utility functions
|
||||
* #
|
||||
* ################################################################ */
|
||||
|
||||
static int dynsec_grouplist__cmp(void *a, void *b)
|
||||
{
|
||||
int prio;
|
||||
struct dynsec__grouplist *grouplist_a = a;
|
||||
struct dynsec__grouplist *grouplist_b = b;
|
||||
|
||||
prio = grouplist_b->priority - grouplist_a->priority;
|
||||
if(prio == 0){
|
||||
return strcmp(grouplist_a->group->groupname, grouplist_b->group->groupname);
|
||||
}else{
|
||||
return prio;
|
||||
}
|
||||
}
|
||||
|
||||
cJSON *dynsec_grouplist__all_to_json(struct dynsec__grouplist *base_grouplist)
|
||||
{
|
||||
struct dynsec__grouplist *grouplist, *grouplist_tmp;
|
||||
cJSON *j_groups, *j_group;
|
||||
|
||||
j_groups = cJSON_CreateArray();
|
||||
if(j_groups == NULL) return NULL;
|
||||
|
||||
HASH_ITER(hh, base_grouplist, grouplist, grouplist_tmp){
|
||||
j_group = cJSON_CreateObject();
|
||||
if(j_group == NULL){
|
||||
cJSON_Delete(j_groups);
|
||||
return NULL;
|
||||
}
|
||||
cJSON_AddItemToArray(j_groups, j_group);
|
||||
|
||||
if(cJSON_AddStringToObject(j_group, "groupname", grouplist->group->groupname) == NULL
|
||||
|| (grouplist->priority != -1 && cJSON_AddIntToObject(j_group, "priority", grouplist->priority) == NULL)
|
||||
){
|
||||
|
||||
cJSON_Delete(j_groups);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return j_groups;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int dynsec_grouplist__add(struct dynsec__grouplist **base_grouplist, struct dynsec__group *group, int priority)
|
||||
{
|
||||
struct dynsec__grouplist *grouplist;
|
||||
|
||||
HASH_FIND(hh, *base_grouplist, group->groupname, strlen(group->groupname), grouplist);
|
||||
if(grouplist != NULL){
|
||||
/* Group is already in the list */
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
grouplist = mosquitto_malloc(sizeof(struct dynsec__grouplist));
|
||||
if(grouplist == NULL){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
grouplist->group = group;
|
||||
grouplist->priority = priority;
|
||||
HASH_ADD_KEYPTR_INORDER(hh, *base_grouplist, grouplist->group->groupname, strlen(grouplist->group->groupname), grouplist, dynsec_grouplist__cmp);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void dynsec_grouplist__cleanup(struct dynsec__grouplist **base_grouplist)
|
||||
{
|
||||
struct dynsec__grouplist *grouplist, *grouplist_tmp;
|
||||
|
||||
HASH_ITER(hh, *base_grouplist, grouplist, grouplist_tmp){
|
||||
HASH_DELETE(hh, *base_grouplist, grouplist);
|
||||
mosquitto_free(grouplist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dynsec_grouplist__remove(struct dynsec__grouplist **base_grouplist, struct dynsec__group *group)
|
||||
{
|
||||
struct dynsec__grouplist *grouplist;
|
||||
|
||||
HASH_FIND(hh, *base_grouplist, group->groupname, strlen(group->groupname), grouplist);
|
||||
if(grouplist){
|
||||
HASH_DELETE(hh, *base_grouplist, grouplist);
|
||||
mosquitto_free(grouplist);
|
||||
}
|
||||
}
|
||||
|
|
@ -68,47 +68,6 @@ static int group_cmp(void *a, void *b)
|
|||
return strcmp(group_a->groupname, group_b->groupname);
|
||||
}
|
||||
|
||||
int dynsec_grouplist__cmp(void *a, void *b)
|
||||
{
|
||||
int prio;
|
||||
struct dynsec__grouplist *grouplist_a = a;
|
||||
struct dynsec__grouplist *grouplist_b = b;
|
||||
|
||||
prio = grouplist_b->priority - grouplist_a->priority;
|
||||
if(prio == 0){
|
||||
return strcmp(grouplist_a->groupname, grouplist_b->groupname);
|
||||
}else{
|
||||
return prio;
|
||||
}
|
||||
}
|
||||
|
||||
cJSON *dynsec_grouplists__all_to_json(struct dynsec__grouplist *base_grouplist)
|
||||
{
|
||||
struct dynsec__grouplist *grouplist, *grouplist_tmp;
|
||||
cJSON *j_groups, *j_group;
|
||||
|
||||
j_groups = cJSON_CreateArray();
|
||||
if(j_groups == NULL) return NULL;
|
||||
|
||||
HASH_ITER(hh, base_grouplist, grouplist, grouplist_tmp){
|
||||
j_group = cJSON_CreateObject();
|
||||
if(j_group == NULL){
|
||||
cJSON_Delete(j_groups);
|
||||
return NULL;
|
||||
}
|
||||
cJSON_AddItemToArray(j_groups, j_group);
|
||||
|
||||
if(cJSON_AddStringToObject(j_group, "groupname", grouplist->group->groupname) == NULL
|
||||
|| (grouplist->priority != -1 && cJSON_AddIntToObject(j_group, "priority", grouplist->priority) == NULL)
|
||||
){
|
||||
|
||||
cJSON_Delete(j_groups);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return j_groups;
|
||||
}
|
||||
|
||||
|
||||
static void group__free_item(struct dynsec__group *group)
|
||||
{
|
||||
|
|
@ -489,7 +448,6 @@ int dynsec_groups__add_client(const char *username, const char *groupname, int p
|
|||
struct dynsec__client *client;
|
||||
struct dynsec__clientlist *clientlist;
|
||||
struct dynsec__group *group;
|
||||
struct dynsec__grouplist *grouplist;
|
||||
int rc;
|
||||
|
||||
client = dynsec_clients__find(username);
|
||||
|
|
@ -512,18 +470,12 @@ int dynsec_groups__add_client(const char *username, const char *groupname, int p
|
|||
if(rc){
|
||||
return rc;
|
||||
}
|
||||
grouplist = mosquitto_malloc(sizeof(struct dynsec__grouplist));
|
||||
if(grouplist == NULL){
|
||||
rc = dynsec_grouplist__add(&client->grouplist, group, priority);
|
||||
if(rc){
|
||||
dynsec_clientlist__remove(&group->clientlist, client);
|
||||
mosquitto_free(grouplist);
|
||||
return MOSQ_ERR_UNKNOWN;
|
||||
return rc;
|
||||
}
|
||||
|
||||
grouplist->groupname = group->groupname;
|
||||
grouplist->group = group;
|
||||
grouplist->priority = priority;
|
||||
HASH_ADD_KEYPTR_INORDER(hh, client->grouplist, grouplist->groupname, strlen(grouplist->groupname), grouplist, dynsec_grouplist__cmp);
|
||||
|
||||
if(update_config){
|
||||
dynsec__config_save();
|
||||
}
|
||||
|
|
@ -576,24 +528,13 @@ int dynsec_groups__process_add_client(cJSON *j_responses, struct mosquitto *cont
|
|||
}
|
||||
|
||||
|
||||
static void dynsec_grouplists__remove(struct dynsec__grouplist **base_grouplist, const char *groupname)
|
||||
{
|
||||
struct dynsec__grouplist *grouplist;
|
||||
|
||||
HASH_FIND(hh, *base_grouplist, groupname, strlen(groupname), grouplist);
|
||||
if(grouplist){
|
||||
HASH_DELETE(hh, *base_grouplist, grouplist);
|
||||
mosquitto_free(grouplist);
|
||||
}
|
||||
}
|
||||
|
||||
static int dynsec__remove_all_clients_from_group(struct dynsec__group *group)
|
||||
{
|
||||
struct dynsec__clientlist *clientlist, *clientlist_tmp;
|
||||
|
||||
HASH_ITER(hh, group->clientlist, clientlist, clientlist_tmp){
|
||||
/* Remove client stored group reference */
|
||||
dynsec_grouplists__remove(&clientlist->client->grouplist, group->groupname);
|
||||
dynsec_grouplist__remove(&clientlist->client->grouplist, group);
|
||||
|
||||
HASH_DELETE(hh, group->clientlist, clientlist);
|
||||
mosquitto_free(clientlist);
|
||||
|
|
@ -618,7 +559,7 @@ int dynsec_groups__remove_client(const char *username, const char *groupname, bo
|
|||
}
|
||||
|
||||
dynsec_clientlist__remove(&group->clientlist, client);
|
||||
dynsec_grouplists__remove(&client->grouplist, groupname);
|
||||
dynsec_grouplist__remove(&client->grouplist, group);
|
||||
|
||||
if(update_config){
|
||||
dynsec__config_save();
|
||||
|
|
|
|||
|
|
@ -118,24 +118,10 @@ int dynsec_rolelists__client_remove_role(struct dynsec__client *client, struct d
|
|||
}
|
||||
|
||||
|
||||
int dynsec_rolelists__group_remove_role(struct dynsec__group *group, struct dynsec__role *role)
|
||||
void dynsec_rolelists__group_remove_role(struct dynsec__group *group, struct dynsec__role *role)
|
||||
{
|
||||
int rc;
|
||||
struct dynsec__grouplist *found_grouplist;
|
||||
|
||||
rc = dynsec_rolelists__remove_role(&group->rolelist, role);
|
||||
if(rc) return rc;
|
||||
|
||||
/* Remove group from role grouplist. */
|
||||
HASH_FIND(hh, role->grouplist, group->groupname, strlen(group->groupname), found_grouplist);
|
||||
if(found_grouplist){
|
||||
HASH_DELETE(hh, role->grouplist, found_grouplist);
|
||||
mosquitto_free(found_grouplist->groupname);
|
||||
mosquitto_free(found_grouplist);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
return MOSQ_ERR_NOT_FOUND;
|
||||
}
|
||||
dynsec_rolelists__remove_role(&group->rolelist, role);
|
||||
dynsec_grouplist__remove(&role->grouplist, group);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -185,35 +171,12 @@ int dynsec_rolelists__client_add_role(struct dynsec__client *client, struct dyns
|
|||
|
||||
int dynsec_rolelists__group_add_role(struct dynsec__group *group, struct dynsec__role *role, int priority)
|
||||
{
|
||||
struct dynsec__rolelist *rolelist;
|
||||
struct dynsec__grouplist *grouplist;
|
||||
int rc;
|
||||
|
||||
rc = dynsec_rolelists__add_role(&group->rolelist, role, priority);
|
||||
if(rc) return rc;
|
||||
|
||||
HASH_FIND(hh, group->rolelist, role->rolename, strlen(role->rolename), rolelist);
|
||||
if(rolelist == NULL){
|
||||
/* This should never happen because the above add_role succeeded. */
|
||||
return MOSQ_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Add group to role grouplist */
|
||||
grouplist = mosquitto_calloc(1, sizeof(struct dynsec__grouplist));
|
||||
if(grouplist == NULL){
|
||||
dynsec_rolelists__remove_role(&group->rolelist, role);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
grouplist->group = group;
|
||||
grouplist->groupname = mosquitto_strdup(group->groupname);
|
||||
if(grouplist->groupname == NULL){
|
||||
dynsec_rolelists__remove_role(&group->rolelist, role);
|
||||
mosquitto_free(grouplist);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
HASH_ADD_KEYPTR_INORDER(hh, role->grouplist, group->groupname, strlen(group->groupname), grouplist, dynsec_grouplist__cmp);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
return dynsec_grouplist__add(&role->grouplist, group, priority);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -295,6 +258,7 @@ static void role__free_item(struct dynsec__role *role, bool remove_from_hash)
|
|||
HASH_DEL(local_roles, role);
|
||||
}
|
||||
dynsec_clientlist__cleanup(&role->clientlist);
|
||||
dynsec_grouplist__cleanup(&role->grouplist);
|
||||
mosquitto_free(role->text_name);
|
||||
mosquitto_free(role->text_description);
|
||||
mosquitto_free(role->rolename);
|
||||
|
|
|
|||
Loading…
Reference in a new issue