From 5b28fac61d47bb150af47c752c9d923e69e1d2ab Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 30 Oct 2020 12:35:02 +0000 Subject: [PATCH] Dynsec: Kick clients on access changes This works in the following circumstances: * client is deleted * client is modified * client has role added * client has role removed * group is deleted * group is modified * group has role added * group has role removed * group has client added * group has client removed * anonymous group is changed The following circumstances are not yet fixed: * role is deleted * role is modified * role has ACL added * role has ACL removed --- plugins/dynamic-security/clients.c | 16 ++++++++++++ plugins/dynamic-security/groups.c | 40 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/plugins/dynamic-security/clients.c b/plugins/dynamic-security/clients.c index 37424fb6..0c4bbeb8 100644 --- a/plugins/dynamic-security/clients.c +++ b/plugins/dynamic-security/clients.c @@ -466,6 +466,10 @@ int dynsec_clients__process_delete(cJSON *j_responses, struct mosquitto *context client__free_item(client); dynsec__config_save(); dynsec__command_reply(j_responses, context, "deleteClient", NULL, correlation_data); + + /* Enforce any changes */ + mosquitto_kick_client_by_username(username, false); + return MOSQ_ERR_SUCCESS; }else{ dynsec__command_reply(j_responses, context, "deleteClient", "Client not found", correlation_data); @@ -634,6 +638,10 @@ int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context dynsec__config_save(); dynsec__command_reply(j_responses, context, "modifyClient", NULL, correlation_data); + + /* Enforce any changes */ + mosquitto_kick_client_by_username(username, false); + return MOSQ_ERR_SUCCESS; } @@ -882,6 +890,10 @@ int dynsec_clients__process_add_role(cJSON *j_responses, struct mosquitto *conte dynsec_rolelists__add_role(&client->rolelist, role, priority); dynsec__config_save(); dynsec__command_reply(j_responses, context, "addClientRole", NULL, correlation_data); + + /* Enforce any changes */ + mosquitto_kick_client_by_username(username, false); + return MOSQ_ERR_SUCCESS; } @@ -917,5 +929,9 @@ int dynsec_clients__process_remove_role(cJSON *j_responses, struct mosquitto *co dynsec_rolelists__remove_role(&client->rolelist, role); dynsec__config_save(); dynsec__command_reply(j_responses, context, "removeClientRole", NULL, correlation_data); + + /* Enforce any changes */ + mosquitto_kick_client_by_username(username, false); + return MOSQ_ERR_SUCCESS; } diff --git a/plugins/dynamic-security/groups.c b/plugins/dynamic-security/groups.c index ac948215..b9739e36 100644 --- a/plugins/dynamic-security/groups.c +++ b/plugins/dynamic-security/groups.c @@ -84,6 +84,15 @@ static int clientlist_cmp(void *a, void *b) return strcmp(clientlist_a->username, clientlist_b->username); } +static void clientlist__kick_all(struct dynsec__clientlist *base_clientlist) +{ + struct dynsec__clientlist *clientlist, *clientlist_tmp; + + HASH_ITER(hh, base_clientlist, clientlist, clientlist_tmp){ + mosquitto_kick_client_by_username(clientlist->client->username, false); + } +} + cJSON *dynsec_clientlists__all_to_json(struct dynsec__clientlist *base_clientlist) { struct dynsec__clientlist *clientlist, *clientlist_tmp; @@ -480,9 +489,16 @@ int dynsec_groups__process_delete(cJSON *j_responses, struct mosquitto *context, group = dynsec_groups__find(groupname); if(group){ + /* Enforce any changes */ + if(group == dynsec_anonymous_group){ + mosquitto_kick_client_by_username(NULL, false); + } + clientlist__kick_all(group->clientlist); + group__free_item(group); dynsec__config_save(); dynsec__command_reply(j_responses, context, "deleteGroup", NULL, correlation_data); + return MOSQ_ERR_SUCCESS; }else{ dynsec__command_reply(j_responses, context, "deleteGroup", "Group not found", correlation_data); @@ -567,6 +583,10 @@ int dynsec_groups__process_add_client(cJSON *j_responses, struct mosquitto *cont }else{ dynsec__command_reply(j_responses, context, "addGroupClient", "Internal error", correlation_data); } + + /* Enforce any changes */ + mosquitto_kick_client_by_username(username, false); + return rc; } @@ -657,6 +677,10 @@ int dynsec_groups__process_remove_client(cJSON *j_responses, struct mosquitto *c }else{ dynsec__command_reply(j_responses, context, "removeGroupClient", "Internal error", correlation_data); } + + /* Enforce any changes */ + mosquitto_kick_client_by_username(username, false); + return rc; } @@ -905,6 +929,12 @@ int dynsec_groups__process_remove_role(cJSON *j_responses, struct mosquitto *con dynsec_rolelists__remove_role(&group->rolelist, role); dynsec__config_save(); dynsec__command_reply(j_responses, context, "removeGroupRole", NULL, correlation_data); + + /* Enforce any changes */ + if(group == dynsec_anonymous_group){ + mosquitto_kick_client_by_username(NULL, false); + } + clientlist__kick_all(group->clientlist); return MOSQ_ERR_SUCCESS; } @@ -985,6 +1015,12 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context, dynsec__config_save(); dynsec__command_reply(j_responses, context, "modifyGroup", NULL, correlation_data); + + /* Enforce any changes */ + if(group == dynsec_anonymous_group){ + mosquitto_kick_client_by_username(NULL, false); + } + clientlist__kick_all(group->clientlist); return MOSQ_ERR_SUCCESS; } @@ -1009,6 +1045,10 @@ int dynsec_groups__process_set_anonymous_group(cJSON *j_responses, struct mosqui dynsec__config_save(); dynsec__command_reply(j_responses, context, "setAnonymousGroup", NULL, correlation_data); + + /* Enforce any changes */ + mosquitto_kick_client_by_username(NULL, false); + return MOSQ_ERR_SUCCESS; }