123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- /*
- Copyright (c) 2009-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 "config.h"
- #include <assert.h>
- #include <string.h>
- #ifdef WIN32
- # include <winsock2.h>
- # include <aclapi.h>
- # include <io.h>
- # include <lmcons.h>
- #else
- # include <sys/stat.h>
- #endif
- #ifdef WITH_BROKER
- #include "mosquitto_broker_internal.h"
- #endif
- #include "mosquitto.h"
- #include "memory_mosq.h"
- #include "net_mosq.h"
- #include "send_mosq.h"
- #include "time_mosq.h"
- #include "tls_mosq.h"
- #include "util_mosq.h"
- /* Check that a topic used for publishing is valid.
- * Search for + or # in a topic. Return MOSQ_ERR_INVAL if found.
- * Also returns MOSQ_ERR_INVAL if the topic string is too long.
- * Returns MOSQ_ERR_SUCCESS if everything is fine.
- */
- int mosquitto_pub_topic_check(const char *str)
- {
- int len = 0;
- #ifdef WITH_BROKER
- int hier_count = 0;
- #endif
- if(str == NULL){
- return MOSQ_ERR_INVAL;
- }
- while(str && str[0]){
- if(str[0] == '+' || str[0] == '#'){
- return MOSQ_ERR_INVAL;
- }
- #ifdef WITH_BROKER
- else if(str[0] == '/'){
- hier_count++;
- }
- #endif
- len++;
- str = &str[1];
- }
- if(len > 65535) return MOSQ_ERR_INVAL;
- #ifdef WITH_BROKER
- if(hier_count > TOPIC_HIERARCHY_LIMIT) return MOSQ_ERR_INVAL;
- #endif
- return MOSQ_ERR_SUCCESS;
- }
- int mosquitto_pub_topic_check2(const char *str, size_t len)
- {
- size_t i;
- #ifdef WITH_BROKER
- int hier_count = 0;
- #endif
- if(str == NULL || len > 65535){
- return MOSQ_ERR_INVAL;
- }
- for(i=0; i<len; i++){
- if(str[i] == '+' || str[i] == '#'){
- return MOSQ_ERR_INVAL;
- }
- #ifdef WITH_BROKER
- else if(str[i] == '/'){
- hier_count++;
- }
- #endif
- }
- #ifdef WITH_BROKER
- if(hier_count > TOPIC_HIERARCHY_LIMIT) return MOSQ_ERR_INVAL;
- #endif
- return MOSQ_ERR_SUCCESS;
- }
- /* Check that a topic used for subscriptions is valid.
- * Search for + or # in a topic, check they aren't in invalid positions such as
- * foo/#/bar, foo/+bar or foo/bar#.
- * Return MOSQ_ERR_INVAL if invalid position found.
- * Also returns MOSQ_ERR_INVAL if the topic string is too long.
- * Returns MOSQ_ERR_SUCCESS if everything is fine.
- */
- int mosquitto_sub_topic_check(const char *str)
- {
- char c = '\0';
- int len = 0;
- #ifdef WITH_BROKER
- int hier_count = 0;
- #endif
- if(str == NULL){
- return MOSQ_ERR_INVAL;
- }
- while(str[0]){
- if(str[0] == '+'){
- if((c != '\0' && c != '/') || (str[1] != '\0' && str[1] != '/')){
- return MOSQ_ERR_INVAL;
- }
- }else if(str[0] == '#'){
- if((c != '\0' && c != '/') || str[1] != '\0'){
- return MOSQ_ERR_INVAL;
- }
- }
- #ifdef WITH_BROKER
- else if(str[0] == '/'){
- hier_count++;
- }
- #endif
- len++;
- c = str[0];
- str = &str[1];
- }
- if(len > 65535) return MOSQ_ERR_INVAL;
- #ifdef WITH_BROKER
- if(hier_count > TOPIC_HIERARCHY_LIMIT) return MOSQ_ERR_INVAL;
- #endif
- return MOSQ_ERR_SUCCESS;
- }
- int mosquitto_sub_topic_check2(const char *str, size_t len)
- {
- char c = '\0';
- size_t i;
- #ifdef WITH_BROKER
- int hier_count = 0;
- #endif
- if(str == NULL || len > 65535){
- return MOSQ_ERR_INVAL;
- }
- for(i=0; i<len; i++){
- if(str[i] == '+'){
- if((c != '\0' && c != '/') || (i<len-1 && str[i+1] != '/')){
- return MOSQ_ERR_INVAL;
- }
- }else if(str[i] == '#'){
- if((c != '\0' && c != '/') || i<len-1){
- return MOSQ_ERR_INVAL;
- }
- }
- #ifdef WITH_BROKER
- else if(str[i] == '/'){
- hier_count++;
- }
- #endif
- c = str[i];
- }
- #ifdef WITH_BROKER
- if(hier_count > TOPIC_HIERARCHY_LIMIT) return MOSQ_ERR_INVAL;
- #endif
- return MOSQ_ERR_SUCCESS;
- }
- int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result)
- {
- return mosquitto_topic_matches_sub2(sub, 0, topic, 0, result);
- }
- /* Does a topic match a subscription? */
- int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *topic, size_t topiclen, bool *result)
- {
- size_t spos;
- UNUSED(sublen);
- UNUSED(topiclen);
- if(!result) return MOSQ_ERR_INVAL;
- *result = false;
- if(!sub || !topic || sub[0] == 0 || topic[0] == 0){
- return MOSQ_ERR_INVAL;
- }
- if((sub[0] == '$' && topic[0] != '$')
- || (topic[0] == '$' && sub[0] != '$')){
- return MOSQ_ERR_SUCCESS;
- }
- spos = 0;
- while(sub[0] != 0){
- if(topic[0] == '+' || topic[0] == '#'){
- return MOSQ_ERR_INVAL;
- }
- if(sub[0] != topic[0] || topic[0] == 0){ /* Check for wildcard matches */
- if(sub[0] == '+'){
- /* Check for bad "+foo" or "a/+foo" subscription */
- if(spos > 0 && sub[-1] != '/'){
- return MOSQ_ERR_INVAL;
- }
- /* Check for bad "foo+" or "foo+/a" subscription */
- if(sub[1] != 0 && sub[1] != '/'){
- return MOSQ_ERR_INVAL;
- }
- spos++;
- sub++;
- while(topic[0] != 0 && topic[0] != '/'){
- if(topic[0] == '+' || topic[0] == '#'){
- return MOSQ_ERR_INVAL;
- }
- topic++;
- }
- if(topic[0] == 0 && sub[0] == 0){
- *result = true;
- return MOSQ_ERR_SUCCESS;
- }
- }else if(sub[0] == '#'){
- /* Check for bad "foo#" subscription */
- if(spos > 0 && sub[-1] != '/'){
- return MOSQ_ERR_INVAL;
- }
- /* Check for # not the final character of the sub, e.g. "#foo" */
- if(sub[1] != 0){
- return MOSQ_ERR_INVAL;
- }else{
- while(topic[0] != 0){
- if(topic[0] == '+' || topic[0] == '#'){
- return MOSQ_ERR_INVAL;
- }
- topic++;
- }
- *result = true;
- return MOSQ_ERR_SUCCESS;
- }
- }else{
- /* Check for e.g. foo/bar matching foo/+/# */
- if(topic[0] == 0
- && spos > 0
- && sub[-1] == '+'
- && sub[0] == '/'
- && sub[1] == '#')
- {
- *result = true;
- return MOSQ_ERR_SUCCESS;
- }
- /* There is no match at this point, but is the sub invalid? */
- while(sub[0] != 0){
- if(sub[0] == '#' && sub[1] != 0){
- return MOSQ_ERR_INVAL;
- }
- spos++;
- sub++;
- }
- /* Valid input, but no match */
- return MOSQ_ERR_SUCCESS;
- }
- }else{
- /* sub[spos] == topic[tpos] */
- if(topic[1] == 0){
- /* Check for e.g. foo matching foo/# */
- if(sub[1] == '/'
- && sub[2] == '#'
- && sub[3] == 0){
- *result = true;
- return MOSQ_ERR_SUCCESS;
- }
- }
- spos++;
- sub++;
- topic++;
- if(sub[0] == 0 && topic[0] == 0){
- *result = true;
- return MOSQ_ERR_SUCCESS;
- }else if(topic[0] == 0 && sub[0] == '+' && sub[1] == 0){
- if(spos > 0 && sub[-1] != '/'){
- return MOSQ_ERR_INVAL;
- }
- spos++;
- sub++;
- *result = true;
- return MOSQ_ERR_SUCCESS;
- }
- }
- }
- if((topic[0] != 0 || sub[0] != 0)){
- *result = false;
- }
- while(topic[0] != 0){
- if(topic[0] == '+' || topic[0] == '#'){
- return MOSQ_ERR_INVAL;
- }
- topic++;
- }
- return MOSQ_ERR_SUCCESS;
- }
|