mirror of
https://github.com/eclipse-mosquitto/mosquitto.git
synced 2026-05-21 12:24:29 +02:00
Add mosquitto_sub_matches_acl()
This moves the sub matching sub code from the dynsec plugin to the library and broker, and removes all of the malloc calls at the same time.
This commit is contained in:
parent
b3045d1adf
commit
e0309acebc
|
|
@ -27,6 +27,11 @@ Broker:
|
|||
- The dynamic security plugin now supports `%c` and `%u` patterns for
|
||||
substituting client id and username respectively, in publishClientSend and
|
||||
publishClientReceive ACLs.
|
||||
- Add `mosquitto_topic_matches_sub_with_pattern()`, which can match against
|
||||
subscriptions with `%c` and `%u` patterns for client id / username
|
||||
substitution.
|
||||
- Add `mosquitto_sub_matches_acl()`, which can match one topic filter (a
|
||||
subscription) against another topic filter (an ACL).
|
||||
|
||||
Client library:
|
||||
- Add MOSQ_OPT_DISABLE_SOCKETPAIR to allow the disabling of the socketpair
|
||||
|
|
@ -41,6 +46,8 @@ Client library:
|
|||
- Add `mosquitto_topic_matches_sub_with_pattern()`, which can match against
|
||||
subscriptions with `%c` and `%u` patterns for client id / username
|
||||
substitution.
|
||||
- Add `mosquitto_sub_matches_acl()`, which can match one topic filter (a
|
||||
subscription) against another topic filter (an ACL).
|
||||
|
||||
Clients:
|
||||
- Add `-o` option for all clients loading options from a specific file.
|
||||
|
|
|
|||
|
|
@ -2495,6 +2495,29 @@ libmosq_EXPORT int mosquitto_topic_matches_sub2(const char *sub, size_t sublen,
|
|||
libmosq_EXPORT int mosquitto_topic_matches_sub_with_pattern(const char *sub, const char *topic, const char *clientid, const char *username, bool *result);
|
||||
|
||||
|
||||
/*
|
||||
* Function: mosquitto_sub_matches_acl
|
||||
*
|
||||
* Check whether a subscription matches an ACL topic filter
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* The subscription $SYS/broker/# would match against the ACL $SYS/#
|
||||
* The subscription $SYS/broker/# would not match against the ACL $SYS/broker/uptime
|
||||
*
|
||||
* Parameters:
|
||||
* acl - topic filter string to check sub against.
|
||||
* sub - subscription topic to check.
|
||||
* result - bool pointer to hold result. Will be set to true if the subscription
|
||||
* matches the acl.
|
||||
*
|
||||
* Returns:
|
||||
* MOSQ_ERR_SUCCESS - on success
|
||||
* MOSQ_ERR_INVAL - if the input parameters were invalid.
|
||||
*/
|
||||
libmosq_EXPORT int mosquitto_sub_matches_acl(const char *sub, const char *topic, bool *result);
|
||||
|
||||
|
||||
/*
|
||||
* Function: mosquitto_pub_topic_check
|
||||
*
|
||||
|
|
|
|||
|
|
@ -146,4 +146,5 @@ MOSQ_2.1 {
|
|||
global:
|
||||
mosquitto_pre_connect_callback_set;
|
||||
mosquitto_topic_matches_sub_with_pattern;
|
||||
mosquitto_sub_matches_acl;
|
||||
} MOSQ_1.7;
|
||||
|
|
|
|||
125
lib/util_topic.c
125
lib/util_topic.c
|
|
@ -354,6 +354,131 @@ static int topic_matches_sub(const char *sub, const char *topic, const char *cli
|
|||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static int sub_matches_acl(const char *acl, const char *sub, bool *result)
|
||||
{
|
||||
size_t apos;
|
||||
|
||||
*result = false;
|
||||
|
||||
if(!acl || !sub || acl[0] == 0 || sub[0] == 0){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
if((acl[0] == '$' && sub[0] != '$')
|
||||
|| (sub[0] == '$' && acl[0] != '$')){
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
apos = 0;
|
||||
|
||||
while(acl[0] != 0){
|
||||
if(acl[0] != sub[0] || sub[0] == 0){ /* Check for wildcard matches */
|
||||
if(acl[0] == '+'){
|
||||
if(sub[0] == '#'){
|
||||
/* + doesn't match # */
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
/* Check for bad "+foo" or "a/+foo" subscription */
|
||||
if(apos > 0 && acl[-1] != '/'){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
/* Check for bad "foo+" or "foo+/a" subscription */
|
||||
if(acl[1] != 0 && acl[1] != '/'){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
apos++;
|
||||
acl++;
|
||||
while(sub[0] != 0 && sub[0] != '/'){
|
||||
sub++;
|
||||
}
|
||||
if(sub[0] == 0 && acl[0] == 0){
|
||||
*result = true;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}else if(acl[0] == '#'){
|
||||
/* Check for bad "foo#" subscription */
|
||||
if(apos > 0 && acl[-1] != '/'){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
/* Check for # not the final character of the sub, e.g. "#foo" */
|
||||
if(acl[1] != 0){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}else{
|
||||
*result = true;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}else{
|
||||
/* Check for e.g. foo/bar matching foo/+/# */
|
||||
if(sub[0] == 0
|
||||
&& apos > 0
|
||||
&& acl[-1] == '+'
|
||||
&& acl[0] == '/'
|
||||
&& acl[1] == '#')
|
||||
{
|
||||
*result = true;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
/* There is no match at this point, but is the sub invalid? */
|
||||
while(acl[0] != 0){
|
||||
if(acl[0] == '#' && acl[1] != 0){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
apos++;
|
||||
acl++;
|
||||
}
|
||||
|
||||
/* Valid input, but no match */
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}else{
|
||||
/* acl[apos] == sub[spos] */
|
||||
if(sub[1] == 0){
|
||||
/* Check for e.g. foo matching foo/# */
|
||||
if(acl[1] == '/'
|
||||
&& acl[2] == '#'
|
||||
&& acl[3] == 0){
|
||||
|
||||
*result = true;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
apos++;
|
||||
acl++;
|
||||
sub++;
|
||||
if(acl[0] == 0 && sub[0] == 0){
|
||||
*result = true;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else if(sub[0] == 0 && acl[0] == '+' && acl[1] == 0){
|
||||
if(apos > 0 && acl[-1] != '/'){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
apos++;
|
||||
acl++;
|
||||
*result = true;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
if((sub[0] != 0 || acl[0] != 0)){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
while(sub[0] != 0){
|
||||
if(sub[0] == '+' || sub[0] == '#'){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
sub++;
|
||||
}
|
||||
|
||||
*result = true;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mosquitto_sub_matches_acl(const char *acl, const char *sub, bool *result)
|
||||
{
|
||||
return sub_matches_acl(acl, sub, result);
|
||||
}
|
||||
|
||||
int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ if(CJSON_FOUND AND WITH_TLS)
|
|||
plugin.c
|
||||
roles.c
|
||||
rolelist.c
|
||||
sub_matches_sub.c
|
||||
)
|
||||
|
||||
target_include_directories(mosquitto_dynamic_security PRIVATE
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ OBJS= \
|
|||
json_help.o \
|
||||
plugin.o \
|
||||
roles.o \
|
||||
rolelist.o \
|
||||
sub_matches_sub.o
|
||||
rolelist.o
|
||||
|
||||
ifeq ($(WITH_CJSON),yes)
|
||||
ifeq ($(WITH_TLS),yes)
|
||||
|
|
@ -64,9 +63,6 @@ roles.o : roles.c dynamic_security.h
|
|||
rolelist.o : rolelist.c dynamic_security.h
|
||||
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) -c $< -o $@
|
||||
|
||||
sub_matches_sub.o : sub_matches_sub.c dynamic_security.h
|
||||
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) -c $< -o $@
|
||||
|
||||
reallyclean : clean
|
||||
clean:
|
||||
-rm -f *.o ${PLUGIN_NAME}.so *.gcda *.gcno
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ static int acl_check_subscribe(struct mosquitto_evt_acl_check *ed, struct dynsec
|
|||
struct dynsec__rolelist *rolelist, *rolelist_tmp = NULL;
|
||||
struct dynsec__acl *acl, *acl_tmp = NULL;
|
||||
size_t len;
|
||||
bool result;
|
||||
|
||||
len = strlen(ed->topic);
|
||||
|
||||
|
|
@ -115,7 +116,8 @@ static int acl_check_subscribe(struct mosquitto_evt_acl_check *ed, struct dynsec
|
|||
}
|
||||
}
|
||||
HASH_ITER(hh, rolelist->role->acls.subscribe_pattern, acl, acl_tmp){
|
||||
if(sub_acl_check(acl->topic, ed->topic)){
|
||||
mosquitto_sub_matches_acl(acl->topic, ed->topic, &result);
|
||||
if(result){
|
||||
if(acl->allow){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
|
|
@ -139,6 +141,7 @@ static int acl_check_unsubscribe(struct mosquitto_evt_acl_check *ed, struct dyns
|
|||
struct dynsec__rolelist *rolelist, *rolelist_tmp = NULL;
|
||||
struct dynsec__acl *acl, *acl_tmp = NULL;
|
||||
size_t len;
|
||||
bool result;
|
||||
|
||||
len = strlen(ed->topic);
|
||||
|
||||
|
|
@ -152,7 +155,8 @@ static int acl_check_unsubscribe(struct mosquitto_evt_acl_check *ed, struct dyns
|
|||
}
|
||||
}
|
||||
HASH_ITER(hh, rolelist->role->acls.unsubscribe_pattern, acl, acl_tmp){
|
||||
if(sub_acl_check(acl->topic, ed->topic)){
|
||||
mosquitto_sub_matches_acl(acl->topic, ed->topic, &result);
|
||||
if(result){
|
||||
if(acl->allow){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
|
|
|
|||
|
|
@ -149,7 +149,6 @@ void dynsec__command_reply(cJSON *j_responses, struct mosquitto *context, const
|
|||
* ################################################################ */
|
||||
|
||||
int dynsec__acl_check_callback(int event, void *event_data, void *userdata);
|
||||
bool sub_acl_check(const char *acl, const char *sub);
|
||||
|
||||
|
||||
/* ################################################################
|
||||
|
|
|
|||
|
|
@ -1,238 +0,0 @@
|
|||
/*
|
||||
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 2.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dynamic_security.h"
|
||||
|
||||
static char *strtok_hier(char *str, char **saveptr)
|
||||
{
|
||||
char *c;
|
||||
|
||||
if(str != NULL){
|
||||
*saveptr = str;
|
||||
}
|
||||
|
||||
if(*saveptr == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c = strchr(*saveptr, '/');
|
||||
if(c){
|
||||
str = *saveptr;
|
||||
*saveptr = c+1;
|
||||
c[0] = '\0';
|
||||
}else if(*saveptr){
|
||||
/* No match, but surplus string */
|
||||
str = *saveptr;
|
||||
*saveptr = NULL;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
static int count_hier_levels(const char *s)
|
||||
{
|
||||
int count = 1;
|
||||
const char *c = s;
|
||||
|
||||
while((c = strchr(c, '/')) && c[0]){
|
||||
c++;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static bool hash_check(char *s, size_t *len)
|
||||
{
|
||||
if((*len) == 1 && s[0] == '#'){
|
||||
s[0] = '\0';
|
||||
(*len)--;
|
||||
return true;
|
||||
}else if((*len) > 1 && s[(*len)-2] == '/' && s[(*len)-1] == '#'){
|
||||
s[(*len)-2] = '\0';
|
||||
s[(*len)-1] = '\0';
|
||||
(*len) -= 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool sub_acl_check(const char *acl, const char *sub)
|
||||
{
|
||||
char *acl_local;
|
||||
char *sub_local;
|
||||
size_t acl_len, sub_len;
|
||||
bool acl_hash = false, sub_hash = false;
|
||||
int acl_levels, sub_levels;
|
||||
int i;
|
||||
char *acl_token, *sub_token;
|
||||
char *acl_saveptr, *sub_saveptr;
|
||||
|
||||
acl_len = strlen(acl);
|
||||
if(acl_len == 1 && acl[0] == '#'){
|
||||
return true;
|
||||
}
|
||||
|
||||
sub_len = strlen(sub);
|
||||
/* mosquitto_validate_utf8(acl, acl_len); */
|
||||
|
||||
acl_local = strdup(acl);
|
||||
sub_local = strdup(sub);
|
||||
if(acl_local == NULL || sub_local == NULL){
|
||||
free(acl_local);
|
||||
free(sub_local);
|
||||
return false;
|
||||
}
|
||||
|
||||
acl_hash = hash_check(acl_local, &acl_len);
|
||||
sub_hash = hash_check(sub_local, &sub_len);
|
||||
|
||||
if(sub_hash == true && acl_hash == false){
|
||||
free(acl_local);
|
||||
free(sub_local);
|
||||
return false;
|
||||
}
|
||||
|
||||
acl_levels = count_hier_levels(acl_local);
|
||||
sub_levels = count_hier_levels(sub_local);
|
||||
if(acl_levels > sub_levels){
|
||||
free(acl_local);
|
||||
free(sub_local);
|
||||
return false;
|
||||
}else if(sub_levels > acl_levels){
|
||||
if(acl_hash == false){
|
||||
free(acl_local);
|
||||
free(sub_local);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
acl_saveptr = acl_local;
|
||||
sub_saveptr = sub_local;
|
||||
for(i=0; i<sub_levels; i++){
|
||||
acl_token = strtok_hier(acl_saveptr, &acl_saveptr);
|
||||
sub_token = strtok_hier(sub_saveptr, &sub_saveptr);
|
||||
|
||||
if(i<acl_levels &&
|
||||
(!strcmp(acl_token, "+")
|
||||
|| !strcmp(acl_token, sub_token))){
|
||||
|
||||
/* This level matches a single level wildcard, or is an exact
|
||||
* match, so carry on checking. */
|
||||
}else if(i>=acl_levels && acl_hash == true){
|
||||
/* The sub has more levels of hierarchy than the acl, but the acl
|
||||
* ends in a multi level wildcard so the match is fine. */
|
||||
}else{
|
||||
free(acl_local);
|
||||
free(sub_local);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
free(acl_local);
|
||||
free(sub_local);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#define BLK "\e[0;30m"
|
||||
#define RED "\e[0;31m"
|
||||
#define GRN "\e[0;32m"
|
||||
#define YEL "\e[0;33m"
|
||||
#define BLU "\e[0;34m"
|
||||
#define MAG "\e[0;35m"
|
||||
#define CYN "\e[0;36m"
|
||||
#define WHT "\e[0;37m"
|
||||
#define RST "\e[0m"
|
||||
|
||||
void hier_test(const char *s, int expected)
|
||||
{
|
||||
int levels;
|
||||
|
||||
levels = count_hier_levels(s);
|
||||
printf("HIER %s %d:%d ", s, expected, levels);
|
||||
if(levels == expected){
|
||||
printf(GRN "passed" RST "\n");
|
||||
}else{
|
||||
printf(RED "failed" RST "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void test(const char *sub1, const char *sub2, bool expected)
|
||||
{
|
||||
bool result;
|
||||
|
||||
printf("ACL %s : %s ", sub1, sub2);
|
||||
result = sub_acl_check(sub1, sub2);
|
||||
if(result == expected){
|
||||
printf(GRN "passed\n" RST);
|
||||
}else{
|
||||
printf(RED "failed\n" RST);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
hier_test("foo/+/bar", 3);
|
||||
hier_test("foo/#", 2);
|
||||
hier_test("foo/+/ba℞/#", 4);
|
||||
hier_test("foo/baz/ba℞", 3);
|
||||
hier_test("foo/+/ba℞/#", 4);
|
||||
hier_test("foo/baz/ba℞/+", 4);
|
||||
hier_test("foo/+/ba℞/#", 4);
|
||||
hier_test("foo/baz/ba℞/#", 4);
|
||||
hier_test("foo/+/ba℞/#", 4);
|
||||
hier_test("foo/baz/+/#", 4);
|
||||
hier_test("/+//#", 4);
|
||||
hier_test("/foo///#", 5);
|
||||
hier_test("#", 1);
|
||||
hier_test("+", 1);
|
||||
hier_test("/", 2);
|
||||
hier_test("////////////////////////////////////////////////////////////////////////////////////////////////////", 101);
|
||||
|
||||
test("foo/+/bar", "foo/#", false);
|
||||
test("foo/+/ba℞/#", "foo/baz/ba℞", true);
|
||||
test("foo/+/ba℞/#", "foo/baz/ba℞/+", true);
|
||||
test("foo/+/ba℞/#", "foo/baz/ba℞/#", true);
|
||||
test("foo/+/ba℞/#", "foo/baz/+/#", false);
|
||||
test("/+//#", "/foo///#", true);
|
||||
test("#", "#", true);
|
||||
test("#", "+", true);
|
||||
test("/#", "+", false);
|
||||
test("/#", "/+", true);
|
||||
test("/+", "#", false);
|
||||
test("/+", "+", false);
|
||||
test("+/+", "topic/topic", true);
|
||||
test("+/+", "topic/topic/", false);
|
||||
test("+", "#", false);
|
||||
test("+", "+", true);
|
||||
test("a/b/c/d/e", "a/b/c/d/e", true);
|
||||
test("a/b/ /d/e", "a/b/c/d/e", false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -30,6 +30,7 @@ _mosquitto_pub_topic_check
|
|||
_mosquitto_realloc
|
||||
_mosquitto_set_username
|
||||
_mosquitto_strdup
|
||||
_mosquitto_sub_matches_acl
|
||||
_mosquitto_sub_topic_check
|
||||
_mosquitto_topic_matches_sub
|
||||
_mosquitto_topic_matches_sub_with_pattern
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
mosquitto_realloc;
|
||||
mosquitto_set_username;
|
||||
mosquitto_strdup;
|
||||
mosquitto_sub_matches_acl;
|
||||
mosquitto_sub_topic_check;
|
||||
mosquitto_topic_matches_sub;
|
||||
mosquitto_topic_matches_sub_with_pattern;
|
||||
|
|
|
|||
|
|
@ -150,6 +150,36 @@ static void TEST_pattern_empty_input(void)
|
|||
CU_ASSERT_EQUAL(match, false);
|
||||
}
|
||||
|
||||
static void TEST_sub_match_empty_input(void)
|
||||
{
|
||||
int rc;
|
||||
bool match;
|
||||
|
||||
rc = mosquitto_sub_matches_acl("sub", NULL, &match);
|
||||
CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL);
|
||||
CU_ASSERT_EQUAL(match, false);
|
||||
|
||||
rc = mosquitto_sub_matches_acl(NULL, "topic", &match);
|
||||
CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL);
|
||||
CU_ASSERT_EQUAL(match, false);
|
||||
|
||||
rc = mosquitto_sub_matches_acl(NULL, NULL, &match);
|
||||
CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL);
|
||||
CU_ASSERT_EQUAL(match, false);
|
||||
|
||||
rc = mosquitto_sub_matches_acl("sub", "", &match);
|
||||
CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL);
|
||||
CU_ASSERT_EQUAL(match, false);
|
||||
|
||||
rc = mosquitto_sub_matches_acl("", "topic", &match);
|
||||
CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL);
|
||||
CU_ASSERT_EQUAL(match, false);
|
||||
|
||||
rc = mosquitto_sub_matches_acl("", "", &match);
|
||||
CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL);
|
||||
CU_ASSERT_EQUAL(match, false);
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* VALID MATCHING AND NON-MATCHING
|
||||
* ======================================================================== */
|
||||
|
|
@ -582,6 +612,50 @@ static void TEST_sub_topic_invalid(void)
|
|||
sub_topic_helper("#/sub/topic", MOSQ_ERR_INVAL);
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* SUB MATCHES ACL
|
||||
* ======================================================================== */
|
||||
|
||||
static void sub_match_test(const char *acl, const char *sub, bool expected, int rc_expected)
|
||||
{
|
||||
bool result;
|
||||
int rc;
|
||||
|
||||
rc = mosquitto_sub_matches_acl(acl, sub, &result);
|
||||
CU_ASSERT_EQUAL(rc, rc_expected);
|
||||
CU_ASSERT_EQUAL(result, expected);
|
||||
}
|
||||
|
||||
|
||||
static void TEST_sub_match_acl(void)
|
||||
{
|
||||
sub_match_test("foo/+/bar", "foo/#", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("foo/+/ba℞/#", "foo/baz/ba℞", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("foo/+/ba℞/#", "foo/baz/ba℞/+", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("foo/+/ba℞/#", "foo/baz/ba℞/#", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("foo/+/ba℞/#", "foo/baz/+/#", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("/+//#", "/foo///#", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("#", "$SYS/uptime", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("$SYS/#", "$SYS/uptime", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("$SYS/+/#", "$SYS/uptime", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("$SYS/+/#", "$SYS/broker/uptime", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("#", "#", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("#", "+", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("/#", "+", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("/#", "/+", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("/+", "#", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("/+", "+", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("+/+", "topic/topic", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("+/+", "topic/topic/", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("+", "#", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("+", "+", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("a/b/c/d/e", "a/b/c/d/e", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("a/b/ /d/e", "a/b/c/d/e", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("a/b/c/d/e", "a/b/c/d/+", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("a/b/c/d/+", "a/b/c/d/e", true, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("a/b/c/d/", "a/b/c/d/+", false, MOSQ_ERR_SUCCESS);
|
||||
sub_match_test("a/b/c/d/+", "a/b/c/d/", true, MOSQ_ERR_SUCCESS);
|
||||
}
|
||||
/* ========================================================================
|
||||
* TEST SUITE SETUP
|
||||
* ======================================================================== */
|
||||
|
|
@ -611,6 +685,8 @@ int init_util_topic_tests(void)
|
|||
|| !CU_add_test(test_suite, "Pattern topic: username", TEST_pattern_username)
|
||||
|| !CU_add_test(test_suite, "Pattern topic: both", TEST_pattern_both)
|
||||
|| !CU_add_test(test_suite, "Pattern topic: wildcard", TEST_pattern_wildcard)
|
||||
|| !CU_add_test(test_suite, "Sub matching: Empty input", TEST_sub_match_empty_input)
|
||||
|| !CU_add_test(test_suite, "Sub matching: normal", TEST_sub_match_acl)
|
||||
){
|
||||
|
||||
printf("Error adding util topic CUnit tests.\n");
|
||||
|
|
@ -619,3 +695,5 @@ int init_util_topic_tests(void)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue