#include #include #include #include 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=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