mirror of
https://github.com/eclipse-mosquitto/mosquitto.git
synced 2026-05-03 00:10:36 +02:00
142 lines
3.9 KiB
C
142 lines
3.9 KiB
C
/*
|
|
Copyright (c) 2011-2021 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 <ctype.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "acl_file.h"
|
|
#include "mosquitto.h"
|
|
|
|
|
|
int acl_file__check(int event, void *event_data, void *userdata)
|
|
{
|
|
struct mosquitto_evt_acl_check *ed = event_data;
|
|
struct acl__user *acl_user;
|
|
struct acl__entry *acl_root;
|
|
bool result;
|
|
struct acl_file_data *data = userdata;
|
|
const char *clientid;
|
|
const char *username;
|
|
|
|
UNUSED(event);
|
|
|
|
// FIXME if(ed->client->bridge) return MOSQ_ERR_SUCCESS;
|
|
if(ed->access == MOSQ_ACL_SUBSCRIBE || ed->access == MOSQ_ACL_UNSUBSCRIBE){
|
|
return MOSQ_ERR_SUCCESS; /* FIXME - implement ACL subscription strings. */
|
|
|
|
}
|
|
clientid = mosquitto_client_id(ed->client);
|
|
username = mosquitto_client_username(ed->client);
|
|
|
|
if(!data->acl_file && !data->acl_users && !data->acl_patterns){
|
|
return MOSQ_ERR_PLUGIN_IGNORE;
|
|
}
|
|
|
|
if(username){
|
|
HASH_FIND(hh, data->acl_users, username, strlen(username), acl_user);
|
|
}else{
|
|
acl_user = &data->acl_anon;
|
|
}
|
|
if(!acl_user && !data->acl_patterns){
|
|
return MOSQ_ERR_ACL_DENIED;
|
|
}
|
|
|
|
if(acl_user){
|
|
acl_root = acl_user->acl;
|
|
}else{
|
|
acl_root = NULL;
|
|
}
|
|
|
|
/* Loop through all ACLs for this client. ACL denials are iterated over first. */
|
|
while(acl_root){
|
|
/* Loop through the topic looking for matches to this ACL. */
|
|
|
|
/* If subscription starts with $, acl_root->topic must also start with $. */
|
|
if(ed->topic[0] == '$' && acl_root->topic[0] != '$'){
|
|
acl_root = acl_root->next;
|
|
continue;
|
|
}
|
|
mosquitto_topic_matches_sub(acl_root->topic, ed->topic, &result);
|
|
if(result){
|
|
if(acl_root->access == MOSQ_ACL_NONE){
|
|
/* Access was explicitly denied for this topic. */
|
|
return MOSQ_ERR_ACL_DENIED;
|
|
}
|
|
if(ed->access & acl_root->access){
|
|
/* And access is allowed. */
|
|
return MOSQ_ERR_SUCCESS;
|
|
}
|
|
}
|
|
acl_root = acl_root->next;
|
|
}
|
|
|
|
acl_root = data->acl_patterns;
|
|
|
|
if(acl_root){
|
|
/* We are using pattern based acls. Check whether the username or
|
|
* client id contains a + or # and if so deny access.
|
|
*
|
|
* Without this, a malicious client may configure its username/client
|
|
* id to bypass ACL checks (or have a username/client id that cannot
|
|
* publish or receive messages to its own place in the hierarchy).
|
|
*/
|
|
if(username && strpbrk(username, "+#")){
|
|
mosquitto_log_printf(MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous username \"%s\"", username);
|
|
return MOSQ_ERR_ACL_DENIED;
|
|
}
|
|
|
|
if(clientid && strpbrk(clientid, "+#")){
|
|
mosquitto_log_printf(MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous client id \"%s\"", clientid);
|
|
return MOSQ_ERR_ACL_DENIED;
|
|
}
|
|
}
|
|
|
|
/* Loop through all pattern ACLs. ACL denial patterns are iterated over first. */
|
|
if(!clientid){
|
|
return MOSQ_ERR_ACL_DENIED;
|
|
}
|
|
|
|
while(acl_root){
|
|
if(acl_root->ucount && !username){
|
|
acl_root = acl_root->next;
|
|
continue;
|
|
}
|
|
|
|
if(mosquitto_topic_matches_sub_with_pattern(acl_root->topic, ed->topic, clientid, username, &result)){
|
|
return MOSQ_ERR_ACL_DENIED;
|
|
}
|
|
if(result){
|
|
if(acl_root->access == MOSQ_ACL_NONE){
|
|
/* Access was explicitly denied for this topic pattern. */
|
|
return MOSQ_ERR_ACL_DENIED;
|
|
}
|
|
if(ed->access & acl_root->access){
|
|
/* And access is allowed. */
|
|
return MOSQ_ERR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
acl_root = acl_root->next;
|
|
}
|
|
|
|
return MOSQ_ERR_ACL_DENIED;
|
|
}
|