Dynsec: Kick affected clients on role change.
This commit is contained in:
parent
9785896eea
commit
3486f0e546
@ -49,6 +49,14 @@ static struct dynsec__client *local_clients = NULL;
|
||||
* #
|
||||
* ################################################################ */
|
||||
|
||||
int dynsec_clientlist__cmp(void *a, void *b)
|
||||
{
|
||||
struct dynsec__clientlist *clientlist_a = a;
|
||||
struct dynsec__clientlist *clientlist_b = b;
|
||||
|
||||
return strcmp(clientlist_a->username, clientlist_b->username);
|
||||
}
|
||||
|
||||
static int client_cmp(void *a, void *b)
|
||||
{
|
||||
struct dynsec__client *client_a = a;
|
||||
@ -243,7 +251,7 @@ int dynsec_clients__config_load(cJSON *tree)
|
||||
if(jtmp && cJSON_IsString(jtmp)){
|
||||
json_get_int(j_role, "priority", &priority, true, -1);
|
||||
role = dynsec_roles__find(jtmp->valuestring);
|
||||
dynsec_rolelists__add_role(&client->rolelist, role, priority);
|
||||
dynsec_rolelists__client_add_role(client, role, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -562,6 +570,23 @@ int dynsec_clients__process_set_password(cJSON *j_responses, struct mosquitto *c
|
||||
}
|
||||
|
||||
|
||||
static void client__add_new_roles(struct dynsec__client *client, struct dynsec__rolelist *base_rolelist)
|
||||
{
|
||||
struct dynsec__rolelist *rolelist, *rolelist_tmp;
|
||||
|
||||
HASH_ITER(hh, base_rolelist, rolelist, rolelist_tmp){
|
||||
dynsec_rolelists__client_add_role(client, rolelist->role, rolelist->priority);
|
||||
}
|
||||
}
|
||||
|
||||
static void client__remove_all_roles(struct dynsec__client *client)
|
||||
{
|
||||
struct dynsec__rolelist *rolelist, *rolelist_tmp;
|
||||
|
||||
HASH_ITER(hh, client->rolelist, rolelist, rolelist_tmp){
|
||||
dynsec_rolelists__client_remove_role(client, rolelist->role);
|
||||
}
|
||||
}
|
||||
|
||||
int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data)
|
||||
{
|
||||
@ -607,8 +632,9 @@ int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context
|
||||
|
||||
rc = dynsec_rolelists__load_from_json(command, &rolelist);
|
||||
if(rc == MOSQ_ERR_SUCCESS){
|
||||
dynsec_rolelists__free_all(&client->rolelist);
|
||||
client->rolelist = rolelist;
|
||||
client__remove_all_roles(client);
|
||||
client__add_new_roles(client, rolelist);
|
||||
dynsec_rolelists__free_all(&rolelist);
|
||||
}else if(rc == MOSQ_ERR_NOT_FOUND){
|
||||
dynsec__command_reply(j_responses, context, "modifyClient", "Role not found", correlation_data);
|
||||
dynsec_rolelists__free_all(&rolelist);
|
||||
@ -848,16 +874,6 @@ int dynsec_clients__process_list(cJSON *j_responses, struct mosquitto *context,
|
||||
}
|
||||
|
||||
|
||||
void dynsec_clients__remove_role_from_all(const struct dynsec__role *role)
|
||||
{
|
||||
struct dynsec__client *client, *client_tmp;
|
||||
|
||||
HASH_ITER(hh, local_clients, client, client_tmp){
|
||||
dynsec_rolelists__remove_role(&client->rolelist, role);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int dynsec_clients__process_add_role(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data)
|
||||
{
|
||||
char *username, *role_name;
|
||||
@ -888,7 +904,7 @@ int dynsec_clients__process_add_role(cJSON *j_responses, struct mosquitto *conte
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
dynsec_rolelists__add_role(&client->rolelist, role, priority);
|
||||
dynsec_rolelists__client_add_role(client, role, priority);
|
||||
dynsec__config_save();
|
||||
dynsec__command_reply(j_responses, context, "addClientRole", NULL, correlation_data);
|
||||
|
||||
@ -927,7 +943,7 @@ int dynsec_clients__process_remove_role(cJSON *j_responses, struct mosquitto *co
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
dynsec_rolelists__remove_role(&client->rolelist, role);
|
||||
dynsec_rolelists__client_remove_role(client, role);
|
||||
dynsec__config_save();
|
||||
dynsec__command_reply(j_responses, context, "removeClientRole", NULL, correlation_data);
|
||||
|
||||
|
@ -114,6 +114,8 @@ struct dynsec__acls{
|
||||
struct dynsec__role{
|
||||
UT_hash_handle hh;
|
||||
struct dynsec__acls acls;
|
||||
struct dynsec__clientlist *clientlist;
|
||||
struct dynsec__grouplist *grouplist;
|
||||
char *rolename;
|
||||
char *text_name;
|
||||
char *text_description;
|
||||
@ -182,9 +184,10 @@ int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context
|
||||
int dynsec_clients__process_remove_role(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
|
||||
int dynsec_clients__process_set_password(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
|
||||
struct dynsec__client *dynsec_clients__find(const char *username);
|
||||
void dynsec_clients__remove_role_from_all(const struct dynsec__role *role);
|
||||
|
||||
cJSON *dynsec_clientlists__all_to_json(struct dynsec__clientlist *base_clientlist);
|
||||
int dynsec_clientlist__cmp(void *a, void *b);
|
||||
void dynsec_clientlist__kick_all(struct dynsec__clientlist *base_clientlist);
|
||||
|
||||
|
||||
|
||||
@ -211,9 +214,9 @@ int dynsec_groups__process_get_anonymous_group(cJSON *j_responses, struct mosqui
|
||||
int dynsec_groups__process_set_anonymous_group(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
|
||||
int dynsec_groups__remove_client(const char *username, const char *groupname, bool update_config);
|
||||
struct dynsec__group *dynsec_groups__find(const char *groupname);
|
||||
void dynsec_groups__remove_role_from_all(const struct dynsec__role *role);
|
||||
|
||||
cJSON *dynsec_grouplists__all_to_json(struct dynsec__grouplist *base_grouplist);
|
||||
int dynsec_grouplist__cmp(void *a, void *b);
|
||||
|
||||
/* ################################################################
|
||||
* #
|
||||
@ -233,9 +236,11 @@ int dynsec_roles__process_modify(cJSON *j_responses, struct mosquitto *context,
|
||||
int dynsec_roles__process_remove_acl(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data);
|
||||
struct dynsec__role *dynsec_roles__find(const char *rolename);
|
||||
|
||||
int dynsec_rolelists__add_role(struct dynsec__rolelist **base_rolelist, struct dynsec__role *role, int priority);
|
||||
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);
|
||||
int dynsec_rolelists__load_from_json(cJSON *command, struct dynsec__rolelist **rolelist);
|
||||
int dynsec_rolelists__remove_role(struct dynsec__rolelist **base_rolelist, const struct dynsec__role *role);
|
||||
void dynsec_rolelists__free_all(struct dynsec__rolelist **base_rolelist);
|
||||
cJSON *dynsec_rolelists__all_to_json(struct dynsec__rolelist *base_rolelist);
|
||||
|
||||
|
@ -68,7 +68,7 @@ static int group_cmp(void *a, void *b)
|
||||
return strcmp(group_a->groupname, group_b->groupname);
|
||||
}
|
||||
|
||||
static int grouplist_cmp(void *a, void *b)
|
||||
int dynsec_grouplist__cmp(void *a, void *b)
|
||||
{
|
||||
struct dynsec__grouplist *grouplist_a = a;
|
||||
struct dynsec__grouplist *grouplist_b = b;
|
||||
@ -76,15 +76,7 @@ static int grouplist_cmp(void *a, void *b)
|
||||
return grouplist_b->priority - grouplist_a->priority;
|
||||
}
|
||||
|
||||
static int clientlist_cmp(void *a, void *b)
|
||||
{
|
||||
struct dynsec__clientlist *clientlist_a = a;
|
||||
struct dynsec__clientlist *clientlist_b = b;
|
||||
|
||||
return strcmp(clientlist_a->username, clientlist_b->username);
|
||||
}
|
||||
|
||||
static void clientlist__kick_all(struct dynsec__clientlist *base_clientlist)
|
||||
void dynsec_clientlist__kick_all(struct dynsec__clientlist *base_clientlist)
|
||||
{
|
||||
struct dynsec__clientlist *clientlist, *clientlist_tmp;
|
||||
|
||||
@ -202,7 +194,7 @@ int dynsec_groups__process_add_role(cJSON *j_responses, struct mosquitto *contex
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
dynsec_rolelists__add_role(&group->rolelist, role, priority);
|
||||
dynsec_rolelists__group_add_role(group, role, priority);
|
||||
dynsec__config_save();
|
||||
dynsec__command_reply(j_responses, context, "addGroupRole", NULL, correlation_data);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
@ -302,7 +294,7 @@ int dynsec_groups__config_load(cJSON *tree)
|
||||
if(j_rolename && cJSON_IsString(j_rolename)){
|
||||
json_get_int(j_role, "priority", &priority, true, -1);
|
||||
role = dynsec_roles__find(j_rolename->valuestring);
|
||||
dynsec_rolelists__add_role(&group->rolelist, role, priority);
|
||||
dynsec_rolelists__group_add_role(group, role, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -493,7 +485,7 @@ int dynsec_groups__process_delete(cJSON *j_responses, struct mosquitto *context,
|
||||
if(group == dynsec_anonymous_group){
|
||||
mosquitto_kick_client_by_username(NULL, false);
|
||||
}
|
||||
clientlist__kick_all(group->clientlist);
|
||||
dynsec_clientlist__kick_all(group->clientlist);
|
||||
|
||||
group__free_item(group);
|
||||
dynsec__config_save();
|
||||
@ -541,12 +533,12 @@ int dynsec_groups__add_client(const char *username, const char *groupname, int p
|
||||
clientlist->username = client->username;
|
||||
clientlist->client = client;
|
||||
clientlist->priority = priority;
|
||||
HASH_ADD_KEYPTR_INORDER(hh, group->clientlist, clientlist->username, strlen(clientlist->username), clientlist, clientlist_cmp);
|
||||
HASH_ADD_KEYPTR_INORDER(hh, group->clientlist, clientlist->username, strlen(clientlist->username), clientlist, dynsec_clientlist__cmp);
|
||||
|
||||
grouplist->groupname = group->groupname;
|
||||
grouplist->group = group;
|
||||
grouplist->priority = priority;
|
||||
HASH_ADD_KEYPTR_INORDER(hh, client->grouplist, grouplist->groupname, strlen(grouplist->groupname), grouplist, grouplist_cmp);
|
||||
HASH_ADD_KEYPTR_INORDER(hh, client->grouplist, grouplist->groupname, strlen(grouplist->groupname), grouplist, dynsec_grouplist__cmp);
|
||||
|
||||
if(update_config){
|
||||
dynsec__config_save();
|
||||
@ -882,22 +874,6 @@ int dynsec_groups__process_get(cJSON *j_responses, struct mosquitto *context, cJ
|
||||
}
|
||||
|
||||
|
||||
void dynsec_groups__remove_role_from_all(const struct dynsec__role *role)
|
||||
{
|
||||
struct dynsec__group *group, *group_tmp;
|
||||
struct dynsec__rolelist *rolelist;
|
||||
|
||||
HASH_ITER(hh, local_groups, group, group_tmp){
|
||||
HASH_FIND(hh, group->rolelist, role->rolename, strlen(role->rolename), rolelist);
|
||||
if(rolelist){
|
||||
HASH_DELETE(hh, group->rolelist, rolelist);
|
||||
mosquitto_free(rolelist->rolename);
|
||||
mosquitto_free(rolelist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int dynsec_groups__process_remove_role(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data)
|
||||
{
|
||||
char *groupname, *rolename;
|
||||
@ -926,7 +902,7 @@ int dynsec_groups__process_remove_role(cJSON *j_responses, struct mosquitto *con
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
dynsec_rolelists__remove_role(&group->rolelist, role);
|
||||
dynsec_rolelists__group_remove_role(group, role);
|
||||
dynsec__config_save();
|
||||
dynsec__command_reply(j_responses, context, "removeGroupRole", NULL, correlation_data);
|
||||
|
||||
@ -934,7 +910,7 @@ int dynsec_groups__process_remove_role(cJSON *j_responses, struct mosquitto *con
|
||||
if(group == dynsec_anonymous_group){
|
||||
mosquitto_kick_client_by_username(NULL, false);
|
||||
}
|
||||
clientlist__kick_all(group->clientlist);
|
||||
dynsec_clientlist__kick_all(group->clientlist);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1020,7 +996,7 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context,
|
||||
if(group == dynsec_anonymous_group){
|
||||
mosquitto_kick_client_by_username(NULL, false);
|
||||
}
|
||||
clientlist__kick_all(group->clientlist);
|
||||
dynsec_clientlist__kick_all(group->clientlist);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,48 @@ int dynsec_rolelists__remove_role(struct dynsec__rolelist **base_rolelist, const
|
||||
}
|
||||
|
||||
|
||||
int dynsec_rolelists__add_role(struct dynsec__rolelist **base_rolelist, struct dynsec__role *role, int priority)
|
||||
int dynsec_rolelists__client_remove_role(struct dynsec__client *client, struct dynsec__role *role)
|
||||
{
|
||||
int rc;
|
||||
struct dynsec__clientlist *found_clientlist;
|
||||
|
||||
rc = dynsec_rolelists__remove_role(&client->rolelist, role);
|
||||
if(rc) return rc;
|
||||
|
||||
HASH_FIND(hh, role->clientlist, client->username, strlen(client->username), found_clientlist);
|
||||
if(found_clientlist){
|
||||
HASH_DELETE(hh, role->clientlist, found_clientlist);
|
||||
mosquitto_free(found_clientlist->username);
|
||||
mosquitto_free(found_clientlist);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
return MOSQ_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int dynsec_rolelists__add_role(struct dynsec__rolelist **base_rolelist, struct dynsec__role *role, int priority)
|
||||
{
|
||||
struct dynsec__rolelist *rolelist;
|
||||
|
||||
@ -118,6 +159,74 @@ int dynsec_rolelists__add_role(struct dynsec__rolelist **base_rolelist, struct d
|
||||
}
|
||||
|
||||
|
||||
int dynsec_rolelists__client_add_role(struct dynsec__client *client, struct dynsec__role *role, int priority)
|
||||
{
|
||||
struct dynsec__rolelist *rolelist;
|
||||
struct dynsec__clientlist *clientlist;
|
||||
int rc;
|
||||
|
||||
rc = dynsec_rolelists__add_role(&client->rolelist, role, priority);
|
||||
if(rc) return rc;
|
||||
|
||||
HASH_FIND(hh, client->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 client to role clientlist */
|
||||
clientlist = mosquitto_calloc(1, sizeof(struct dynsec__clientlist));
|
||||
if(clientlist == NULL){
|
||||
dynsec_rolelists__remove_role(&client->rolelist, role);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
clientlist->client = client;
|
||||
clientlist->username = mosquitto_strdup(client->username);
|
||||
if(clientlist->username == NULL){
|
||||
dynsec_rolelists__remove_role(&client->rolelist, role);
|
||||
mosquitto_free(clientlist);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
HASH_ADD_KEYPTR_INORDER(hh, role->clientlist, client->username, strlen(client->username), clientlist, dynsec_clientlist__cmp);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
int dynsec_rolelists__load_from_json(cJSON *command, struct dynsec__rolelist **rolelist)
|
||||
{
|
||||
cJSON *j_roles, *j_role, *j_rolename;
|
||||
@ -228,6 +337,21 @@ void dynsec_roles__cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
static void role__kick_all(struct dynsec__role *role)
|
||||
{
|
||||
struct dynsec__grouplist *grouplist, *grouplist_tmp;
|
||||
|
||||
dynsec_clientlist__kick_all(role->clientlist);
|
||||
|
||||
HASH_ITER(hh, role->grouplist, grouplist, grouplist_tmp){
|
||||
if(grouplist->group == dynsec_anonymous_group){
|
||||
mosquitto_kick_client_by_username(NULL, false);
|
||||
}
|
||||
dynsec_clientlist__kick_all(grouplist->group->clientlist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ################################################################
|
||||
* #
|
||||
* # Config file load and save
|
||||
@ -528,6 +652,31 @@ error:
|
||||
}
|
||||
|
||||
|
||||
static void role__remove_all_clients(struct dynsec__role *role)
|
||||
{
|
||||
struct dynsec__clientlist *clientlist, *clientlist_tmp;
|
||||
|
||||
HASH_ITER(hh, role->clientlist, clientlist, clientlist_tmp){
|
||||
mosquitto_kick_client_by_username(clientlist->username, false);
|
||||
|
||||
dynsec_rolelists__client_remove_role(clientlist->client, role);
|
||||
}
|
||||
}
|
||||
|
||||
static void role__remove_all_groups(struct dynsec__role *role)
|
||||
{
|
||||
struct dynsec__grouplist *grouplist, *grouplist_tmp;
|
||||
|
||||
HASH_ITER(hh, role->grouplist, grouplist, grouplist_tmp){
|
||||
if(grouplist->group == dynsec_anonymous_group){
|
||||
mosquitto_kick_client_by_username(NULL, false);
|
||||
}
|
||||
dynsec_clientlist__kick_all(grouplist->group->clientlist);
|
||||
|
||||
dynsec_rolelists__group_remove_role(grouplist->group, role);
|
||||
}
|
||||
}
|
||||
|
||||
int dynsec_roles__process_delete(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data)
|
||||
{
|
||||
char *rolename;
|
||||
@ -540,8 +689,8 @@ int dynsec_roles__process_delete(cJSON *j_responses, struct mosquitto *context,
|
||||
|
||||
role = dynsec_roles__find(rolename);
|
||||
if(role){
|
||||
dynsec_clients__remove_role_from_all(role);
|
||||
dynsec_groups__remove_role_from_all(role);
|
||||
role__remove_all_clients(role);
|
||||
role__remove_all_groups(role);
|
||||
role__free_item(role, true);
|
||||
dynsec__config_save();
|
||||
dynsec__command_reply(j_responses, context, "deleteRole", NULL, correlation_data);
|
||||
@ -736,6 +885,8 @@ int dynsec_roles__process_add_acl(cJSON *j_responses, struct mosquitto *context,
|
||||
dynsec__config_save();
|
||||
dynsec__command_reply(j_responses, context, "addRoleACL", NULL, correlation_data);
|
||||
|
||||
role__kick_all(role);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -790,6 +941,8 @@ int dynsec_roles__process_remove_acl(cJSON *j_responses, struct mosquitto *conte
|
||||
role__free_acl(acllist, acl);
|
||||
dynsec__config_save();
|
||||
dynsec__command_reply(j_responses, context, "removeRoleACL", NULL, correlation_data);
|
||||
|
||||
role__kick_all(role);
|
||||
}else{
|
||||
dynsec__command_reply(j_responses, context, "removeRoleACL", "ACL not found", correlation_data);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user