dynsec: Fix potential grouplist leaks.

This commit is contained in:
Roger A. Light 2020-11-18 11:45:31 +00:00
parent 04d53e8919
commit fe436cda95
7 changed files with 169 additions and 111 deletions

View file

@ -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

View file

@ -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 $@

View file

@ -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;

View file

@ -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);

View 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);
}
}

View file

@ -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();

View file

@ -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);