#include #include #include "ota_url_policy.h" #define BANBAN_OTA_LEGACY_URL_PREFIX \ "http://101.35.224.118:8080/assets/firmware/" #define BANBAN_OTA_BASE_DOMAIN "talkingq.com" static int banban_ascii_equal_nocase(const char *left, const char *right, size_t length) { size_t i; for (i = 0; i < length; ++i) { unsigned char a = (unsigned char)left[i]; unsigned char b = (unsigned char)right[i]; if (a >= 'A' && a <= 'Z') { a = (unsigned char)(a + ('a' - 'A')); } if (b >= 'A' && b <= 'Z') { b = (unsigned char)(b + ('a' - 'A')); } if (a != b) { return 0; } } return 1; } static int banban_hostname_is_valid(const char *host, size_t host_length) { size_t i; int label_has_character = 0; int previous_was_hyphen = 0; if (host_length == 0 || host_length > 253) { return 0; } for (i = 0; i < host_length; ++i) { unsigned char character = (unsigned char)host[i]; if ((character >= 'A' && character <= 'Z') || (character >= 'a' && character <= 'z') || (character >= '0' && character <= '9')) { label_has_character = 1; previous_was_hyphen = 0; continue; } if (character == '-') { if (!label_has_character) { return 0; } previous_was_hyphen = 1; continue; } if (character == '.') { if (!label_has_character || previous_was_hyphen) { return 0; } label_has_character = 0; previous_was_hyphen = 0; continue; } return 0; } return label_has_character && !previous_was_hyphen; } static int banban_host_is_talkingq(const char *host, size_t host_length) { const size_t base_length = sizeof(BANBAN_OTA_BASE_DOMAIN) - 1; if (!banban_hostname_is_valid(host, host_length)) { return 0; } if (host_length == base_length) { return banban_ascii_equal_nocase(host, BANBAN_OTA_BASE_DOMAIN, base_length); } if (host_length <= base_length + 1 || host[host_length - base_length - 1] != '.') { return 0; } return banban_ascii_equal_nocase(host + host_length - base_length, BANBAN_OTA_BASE_DOMAIN, base_length); } static int banban_port_is_valid(const char *port, size_t port_length) { size_t i; unsigned long value = 0; if (port_length == 0 || port_length > 5) { return 0; } for (i = 0; i < port_length; ++i) { if (port[i] < '0' || port[i] > '9') { return 0; } value = value * 10 + (unsigned long)(port[i] - '0'); } return value > 0 && value <= 65535; } static int banban_path_is_fbf(const char *path) { const char *path_end; const char *query; if (path == NULL || path[0] != '/' || path[1] == '\0' || strstr(path, "..") != NULL || strchr(path, '\\') != NULL || strchr(path, '#') != NULL) { return 0; } query = strchr(path, '?'); path_end = query != NULL ? query : path + strlen(path); if ((size_t)(path_end - path) < 4) { return 0; } return banban_ascii_equal_nocase(path_end - 4, ".bin", 4); } int banban_ota_url_is_allowed(const char *url) { const char *authority; const char *path; const char *host_end; const char *colon; const size_t legacy_prefix_length = sizeof(BANBAN_OTA_LEGACY_URL_PREFIX) - 1; if (url == NULL || url[0] == '\0') { return 0; } if (strncmp(url, BANBAN_OTA_LEGACY_URL_PREFIX, legacy_prefix_length) == 0) { return banban_path_is_fbf(url + legacy_prefix_length - 1); } if (strncmp(url, "http://", 7) == 0) { authority = url + 7; } else if (strncmp(url, "https://", 8) == 0) { authority = url + 8; } else { return 0; } path = strchr(authority, '/'); if (path == NULL || path == authority) { return 0; } if (memchr(authority, '@', (size_t)(path - authority)) != NULL) { return 0; } colon = memchr(authority, ':', (size_t)(path - authority)); host_end = colon != NULL ? colon : path; if (!banban_host_is_talkingq(authority, (size_t)(host_end - authority))) { return 0; } if (colon != NULL && !banban_port_is_valid(colon + 1, (size_t)(path - colon - 1))) { return 0; } return banban_path_is_fbf(path); }