forked from jpmens/mosquitto-auth-plug
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbackends.c
209 lines (182 loc) · 6.07 KB
/
backends.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/*
* Copyright (c) 2014 Jan-Piet Mens <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions
* in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of mosquitto
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "backends.h"
#include "mosquitto.h"
/*
* Search through `in' for tokens %c (clientid) and %u (username); build a
* new malloc'd string at `res' with those tokens interpolated into it.
*/
void t_expand(const char *clientid, const char *username, const char *in, char **res)
{
const char *s;
char *work, *wp;
int c_specials = 0, u_specials = 0, len;
const char *ct, *ut;
ct = (clientid) ? clientid : "";
ut = (username) ? username : "";
for (s = in; s && *s; s++) {
if (*s == '%' && (*(s + 1) == 'c'))
c_specials++;
if (*s == '%' && (*(s + 1) == 'u'))
u_specials++;
}
len = strlen(in) + 1;
len += strlen(clientid) * c_specials;
len += strlen(username) * u_specials;
if ((work = malloc(len)) == NULL) {
*res = NULL;
return;
}
for (s = in, wp = work; s && *s; s++) {
*wp++ = *s;
if (*s == '%' && (*(s + 1) == 'c')) {
*--wp = 0;
strcpy(wp, ct);
wp += strlen(ct);
s++;
}
if (*s == '%' && (*(s + 1) == 'u')) {
*--wp = 0;
strcpy(wp, ut);
wp += strlen(ut);
s++;
}
}
*wp = 0;
*res = work;
}
/*
* Compares an ACL topic filter with a requested subscribe filter to see if the subscription is allowed.
* Sets *result to 1 if a match is found and false otherwise.
*/
int mosquitto_auth_sub_topic_matches_acl(const char *acl_topic, const char *req_topic, int *result)
{
if(!result) {
*result = FALSE;
return MOSQ_ERR_INVAL;
}
if(!req_topic || !acl_topic) {
*result = FALSE;
return MOSQ_ERR_INVAL;
}
if(mosquitto_sub_topic_check(req_topic) != MOSQ_ERR_SUCCESS) {
*result = FALSE;
return MOSQ_ERR_INVAL;
}
if(mosquitto_sub_topic_check(acl_topic) != MOSQ_ERR_SUCCESS) {
*result = FALSE;
return MOSQ_ERR_INVAL;
}
if((*req_topic == '$' && *acl_topic != '$') || (*acl_topic == '$' && *req_topic != '$')) {
*result = FALSE;
return MOSQ_ERR_SUCCESS;
}
while(*req_topic && *acl_topic) {
int check_equiv;
//Process the # if it exists here.
if(*acl_topic == '#') {
//No need to check any further. The ACL has a #.
*result = TRUE;
return MOSQ_ERR_SUCCESS;
} else if(*req_topic == '#') {
//The user subscribed with a #, but the ACL does not allow that.
*result = FALSE;
return MOSQ_ERR_SUCCESS;
}
//Process the + if it exists here.
if(*req_topic == '+') {
//The subscription includes a single-level wild card. Check to see if that is allowed.
if(*acl_topic == '+') {
//The ACL allows for a + here. We need to move on to the next level without checking for equivalence.
check_equiv = FALSE;
} else {
//The ACL doesn't allow for a + in this position.
*result = FALSE;
return MOSQ_ERR_SUCCESS;
}
} else {
//We are just looking at normal subscription level.
//If the ACL has a single level wildcard, no need to check anything else at this level.
if(*acl_topic == '+') {
//The ACL allows for a + here. We need to move on to the next level without checking for equivalence.
check_equiv = FALSE;
} else {
//No wildcards. We need to compare to make sure the topic level for both topic filters are identical.
check_equiv = TRUE;
}
}
//Get the length of the current sub topic level.
int sub_level_length = 0;
while(req_topic[sub_level_length] && (req_topic[sub_level_length] != '/')) {
sub_level_length++;
}
//Get the length of the current acl topic level.
int acl_level_length = 0;
while(acl_topic[acl_level_length] && (acl_topic[acl_level_length] != '/')) {
acl_level_length++;
}
//If we need to check for equivalency, do so.
if(check_equiv) {
//First check to see if the lengths of the levels are identical. If not, we know we don't have a match.
if(sub_level_length != acl_level_length) {
*result = FALSE;
return MOSQ_ERR_SUCCESS;
}
//Lengths are the same, so we need to check the contents.
if(memcmp(req_topic, acl_topic, sub_level_length)) {
*result = FALSE;
return MOSQ_ERR_SUCCESS;
}
} else {
}
//Increment pointers
req_topic += sub_level_length;
acl_topic += acl_level_length;
//If we haven't incremented to the null terminator, go one more to get past the '/'.
// Only do this if both topics have not reached the end to avoid covering up situation
// where one topic is longer than the other.
if(*req_topic && *acl_topic) {
req_topic++;
acl_topic++;
}
}
//If we hit the null terminator on one and not the other, we don't have a match.
if((*req_topic != 0) ^ (*acl_topic != 0))
{
*result = FALSE;
return MOSQ_ERR_SUCCESS;
}
//Topics match.
*result = TRUE;
return MOSQ_ERR_SUCCESS;
}