From 801e31efda6058d0757d487b7e7e1015a95743a7 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 4 Nov 2020 13:32:27 +0000 Subject: [PATCH] Dynsec: Validate user/group/role names as UTF-8. --- plugins/dynamic-security/clients.c | 54 +++++++++++++++++++++++++-- plugins/dynamic-security/groups.c | 59 ++++++++++++++++++++++++++++-- plugins/dynamic-security/roles.c | 28 +++++++++++++- src/linker-macosx.syms | 1 + src/linker.syms | 1 + 5 files changed, 135 insertions(+), 8 deletions(-) diff --git a/plugins/dynamic-security/clients.c b/plugins/dynamic-security/clients.c index df024d3e..3c5a1ffd 100644 --- a/plugins/dynamic-security/clients.c +++ b/plugins/dynamic-security/clients.c @@ -341,7 +341,7 @@ int dynsec_clients__config_save(cJSON *tree) int dynsec_clients__process_create(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) { - char *username, *password, *clientid; + char *username, *password, *clientid = NULL; char *text_name, *text_description; struct dynsec__client *client; int rc; @@ -352,6 +352,10 @@ int dynsec_clients__process_create(cJSON *j_responses, struct mosquitto *context dynsec__command_reply(j_responses, context, "createClient", "Invalid/missing username", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(username, (int)strlen(username)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "createClient", "Username not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } if(json_get_string(command, "password", &password, true) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "createClient", "Invalid/missing password", correlation_data); @@ -362,6 +366,11 @@ int dynsec_clients__process_create(cJSON *j_responses, struct mosquitto *context dynsec__command_reply(j_responses, context, "createClient", "Invalid/missing client id", correlation_data); return MOSQ_ERR_INVAL; } + if(clientid && mosquitto_validate_utf8(clientid, (int)strlen(clientid)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "createClient", "Client ID not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } + if(json_get_string(command, "textname", &text_name, true) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "createClient", "Invalid/missing textname", correlation_data); @@ -494,6 +503,10 @@ int dynsec_clients__process_disable(cJSON *j_responses, struct mosquitto *contex dynsec__command_reply(j_responses, context, "disableClient", "Invalid/missing username", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(username, (int)strlen(username)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "disableClient", "Username not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } client = dynsec_clients__find(username); if(client == NULL){ @@ -520,6 +533,10 @@ int dynsec_clients__process_enable(cJSON *j_responses, struct mosquitto *context dynsec__command_reply(j_responses, context, "enableClient", "Invalid/missing username", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(username, (int)strlen(username)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "enableClient", "Username not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } client = dynsec_clients__find(username); if(client == NULL){ @@ -544,6 +561,10 @@ int dynsec_clients__process_set_password(cJSON *j_responses, struct mosquitto *c dynsec__command_reply(j_responses, context, "setClientPassword", "Invalid/missing username", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(username, (int)strlen(username)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "setClientPassword", "Username not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } if(json_get_string(command, "password", &password, false) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "setClientPassword", "Invalid/missing password", correlation_data); @@ -603,6 +624,10 @@ int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context dynsec__command_reply(j_responses, context, "modifyClient", "Invalid/missing username", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(username, (int)strlen(username)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "modifyClient", "Username not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } client = dynsec_clients__find(username); if(client == NULL){ @@ -742,6 +767,10 @@ int dynsec_clients__process_get(cJSON *j_responses, struct mosquitto *context, c dynsec__command_reply(j_responses, context, "getClient", "Invalid/missing username", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(username, (int)strlen(username)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "getClient", "Username not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } client = dynsec_clients__find(username); if(client == NULL){ @@ -876,7 +905,7 @@ int dynsec_clients__process_list(cJSON *j_responses, struct mosquitto *context, int dynsec_clients__process_add_role(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) { - char *username, *role_name; + char *username, *rolename; struct dynsec__client *client; struct dynsec__role *role; int priority; @@ -885,11 +914,19 @@ int dynsec_clients__process_add_role(cJSON *j_responses, struct mosquitto *conte dynsec__command_reply(j_responses, context, "addClientRole", "Invalid/missing username", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(username, (int)strlen(username)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "addClientRole", "Username not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } - if(json_get_string(command, "rolename", &role_name, false) != MOSQ_ERR_SUCCESS){ + if(json_get_string(command, "rolename", &rolename, false) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "addClientRole", "Invalid/missing rolename", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(rolename, (int)strlen(rolename)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "addClientRole", "Role name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } json_get_int(command, "priority", &priority, true, -1); client = dynsec_clients__find(username); @@ -898,7 +935,7 @@ int dynsec_clients__process_add_role(cJSON *j_responses, struct mosquitto *conte return MOSQ_ERR_SUCCESS; } - role = dynsec_roles__find(role_name); + role = dynsec_roles__find(rolename); if(role == NULL){ dynsec__command_reply(j_responses, context, "addClientRole", "Role not found", correlation_data); return MOSQ_ERR_SUCCESS; @@ -925,11 +962,20 @@ int dynsec_clients__process_remove_role(cJSON *j_responses, struct mosquitto *co dynsec__command_reply(j_responses, context, "removeClientRole", "Invalid/missing username", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(username, (int)strlen(username)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "removeClientRole", "Username not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } if(json_get_string(command, "rolename", &rolename, false) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "removeGroupRole", "Invalid/missing rolename", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(rolename, (int)strlen(rolename)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "removeClientRole", "Role name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } + client = dynsec_clients__find(username); if(client == NULL){ diff --git a/plugins/dynamic-security/groups.c b/plugins/dynamic-security/groups.c index c879ed9f..4659d731 100644 --- a/plugins/dynamic-security/groups.c +++ b/plugins/dynamic-security/groups.c @@ -166,7 +166,7 @@ struct dynsec__group *dynsec_groups__find(const char *groupname) int dynsec_groups__process_add_role(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) { - char *groupname, *role_name; + char *groupname, *rolename; struct dynsec__group *group; struct dynsec__role *role; int priority; @@ -175,11 +175,19 @@ int dynsec_groups__process_add_role(cJSON *j_responses, struct mosquitto *contex dynsec__command_reply(j_responses, context, "addGroupRole", "Invalid/missing groupname", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(groupname, (int)strlen(groupname)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "addGroupRole", "Group name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } - if(json_get_string(command, "roleName", &role_name, false) != MOSQ_ERR_SUCCESS){ + if(json_get_string(command, "roleName", &rolename, false) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "addGroupRole", "Invalid/missing roleName", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(rolename, (int)strlen(rolename)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "addGroupRole", "Role name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } json_get_int(command, "priority", &priority, true, -1); group = dynsec_groups__find(groupname); @@ -188,7 +196,7 @@ int dynsec_groups__process_add_role(cJSON *j_responses, struct mosquitto *contex return MOSQ_ERR_SUCCESS; } - role = dynsec_roles__find(role_name); + role = dynsec_roles__find(rolename); if(role == NULL){ dynsec__command_reply(j_responses, context, "addGroupRole", "Role not found", correlation_data); return MOSQ_ERR_SUCCESS; @@ -404,6 +412,10 @@ int dynsec_groups__process_create(cJSON *j_responses, struct mosquitto *context, dynsec__command_reply(j_responses, context, "createGroup", "Invalid/missing groupname", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(groupname, (int)strlen(groupname)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "createGroup", "Group name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } if(json_get_string(command, "textname", &text_name, true) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "createGroup", "Invalid/missing textname", correlation_data); @@ -478,6 +490,10 @@ int dynsec_groups__process_delete(cJSON *j_responses, struct mosquitto *context, dynsec__command_reply(j_responses, context, "deleteGroup", "Invalid/missing groupname", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(groupname, (int)strlen(groupname)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "deleteGroup", "Group name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } group = dynsec_groups__find(groupname); if(group){ @@ -558,11 +574,20 @@ int dynsec_groups__process_add_client(cJSON *j_responses, struct mosquitto *cont dynsec__command_reply(j_responses, context, "addGroupClient", "Invalid/missing username", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(username, (int)strlen(username)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "addGroupClient", "Username not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } if(json_get_string(command, "groupname", &groupname, false) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "addGroupClient", "Invalid/missing groupname", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(groupname, (int)strlen(groupname)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "addGroupClient", "Group name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } + json_get_int(command, "priority", &priority, true, -1); rc = dynsec_groups__add_client(username, groupname, priority, true); @@ -653,11 +678,19 @@ int dynsec_groups__process_remove_client(cJSON *j_responses, struct mosquitto *c dynsec__command_reply(j_responses, context, "removeGroupClient", "Invalid/missing username", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(username, (int)strlen(username)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "removeGroupClient", "Username not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } if(json_get_string(command, "groupname", &groupname, false) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "removeGroupClient", "Invalid/missing groupname", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(groupname, (int)strlen(groupname)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "removeGroupClient", "Group name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } rc = dynsec_groups__remove_client(username, groupname, true); if(rc == MOSQ_ERR_SUCCESS){ @@ -825,6 +858,10 @@ int dynsec_groups__process_get(cJSON *j_responses, struct mosquitto *context, cJ dynsec__command_reply(j_responses, context, "getGroup", "Invalid/missing groupname", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(groupname, (int)strlen(groupname)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "getGroup", "Group name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } tree = cJSON_CreateObject(); if(tree == NULL){ @@ -884,11 +921,19 @@ int dynsec_groups__process_remove_role(cJSON *j_responses, struct mosquitto *con dynsec__command_reply(j_responses, context, "removeGroupRole", "Invalid/missing groupname", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(groupname, (int)strlen(groupname)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "removeGroupRole", "Group name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } if(json_get_string(command, "roleName", &rolename, false) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "removeGroupRole", "Invalid/missing roleName", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(rolename, (int)strlen(rolename)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "removeGroupRole", "Role name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } group = dynsec_groups__find(groupname); if(group == NULL){ @@ -930,6 +975,10 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context, dynsec__command_reply(j_responses, context, "modifyGroup", "Invalid/missing groupname", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(groupname, (int)strlen(groupname)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "modifyGroup", "Group name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } group = dynsec_groups__find(groupname); if(group == NULL){ @@ -1010,6 +1059,10 @@ int dynsec_groups__process_set_anonymous_group(cJSON *j_responses, struct mosqui dynsec__command_reply(j_responses, context, "setAnonymousGroup", "Invalid/missing groupname", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(groupname, (int)strlen(groupname)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "setAnonymousGroup", "Group name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } group = dynsec_groups__find(groupname); if(group == NULL){ diff --git a/plugins/dynamic-security/roles.c b/plugins/dynamic-security/roles.c index 09769309..afefdcb1 100644 --- a/plugins/dynamic-security/roles.c +++ b/plugins/dynamic-security/roles.c @@ -575,6 +575,10 @@ int dynsec_roles__process_create(cJSON *j_responses, struct mosquitto *context, dynsec__command_reply(j_responses, context, "createRole", "Invalid/missing rolename", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(rolename, (int)strlen(rolename)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "createRole", "Role name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } if(json_get_string(command, "textname", &text_name, true) != MOSQ_ERR_SUCCESS){ dynsec__command_reply(j_responses, context, "createRole", "Invalid/missing textname", correlation_data); @@ -686,6 +690,10 @@ int dynsec_roles__process_delete(cJSON *j_responses, struct mosquitto *context, dynsec__command_reply(j_responses, context, "deleteRole", "Invalid/missing rolename", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(rolename, (int)strlen(rolename)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "deleteRole", "Role name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } role = dynsec_roles__find(rolename); if(role){ @@ -825,6 +833,11 @@ int dynsec_roles__process_add_acl(cJSON *j_responses, struct mosquitto *context, dynsec__command_reply(j_responses, context, "addRoleACL", "Invalid/missing rolename", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(rolename, (int)strlen(rolename)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "addRoleACL", "Role name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } + role = dynsec_roles__find(rolename); if(role == NULL){ dynsec__command_reply(j_responses, context, "addRoleACL", "Role not found", correlation_data); @@ -910,9 +923,14 @@ int dynsec_roles__process_remove_acl(cJSON *j_responses, struct mosquitto *conte int rc; if(json_get_string(command, "rolename", &rolename, false) != MOSQ_ERR_SUCCESS){ - dynsec__command_reply(j_responses, context, "createRole", "Invalid/missing rolename", correlation_data); + dynsec__command_reply(j_responses, context, "removeRoleACL", "Invalid/missing rolename", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(rolename, (int)strlen(rolename)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "removeRoleACL", "Role name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } + role = dynsec_roles__find(rolename); if(role == NULL){ dynsec__command_reply(j_responses, context, "removeRoleACL", "Role not found", correlation_data); @@ -979,6 +997,10 @@ int dynsec_roles__process_get(cJSON *j_responses, struct mosquitto *context, cJS dynsec__command_reply(j_responses, context, "getRole", "Invalid/missing rolename", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(rolename, (int)strlen(rolename)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "getRole", "Role name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } role = dynsec_roles__find(rolename); if(role == NULL){ @@ -1047,6 +1069,10 @@ int dynsec_roles__process_modify(cJSON *j_responses, struct mosquitto *context, dynsec__command_reply(j_responses, context, "modifyRole", "Invalid/missing rolename", correlation_data); return MOSQ_ERR_INVAL; } + if(mosquitto_validate_utf8(rolename, (int)strlen(rolename)) != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "modifyRole", "Role name not valid UTF-8", correlation_data); + return MOSQ_ERR_INVAL; + } role = dynsec_roles__find(rolename); if(role == NULL){ diff --git a/src/linker-macosx.syms b/src/linker-macosx.syms index 19193362..c9311c41 100644 --- a/src/linker-macosx.syms +++ b/src/linker-macosx.syms @@ -33,3 +33,4 @@ _mosquitto_set_username _mosquitto_strdup _mosquitto_sub_topic_check _mosquitto_topic_matches_sub +_mosquitto_validate_utf8 diff --git a/src/linker.syms b/src/linker.syms index 8bf2f790..8638f738 100644 --- a/src/linker.syms +++ b/src/linker.syms @@ -34,4 +34,5 @@ mosquitto_strdup; mosquitto_sub_topic_check; mosquitto_topic_matches_sub; + mosquitto_validate_utf8; };