blob: 66050943b7c61af5f472afee13824c8efe0f3ccb [file] [log] [blame]
Willy Tarreaua84d3742007-05-07 00:36:48 +02001/*
2 * ACL management functions.
3 *
Willy Tarreau11382812008-07-09 16:18:21 +02004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaua84d3742007-05-07 00:36:48 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreauae8b7962007-06-09 23:10:04 +020013#include <ctype.h>
Willy Tarreaua84d3742007-05-07 00:36:48 +020014#include <stdio.h>
15#include <string.h>
16
17#include <common/config.h>
18#include <common/mini-clist.h>
19#include <common/standard.h>
20
21#include <proto/acl.h>
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +010022#include <proto/auth.h>
Willy Tarreau404e8ab2009-07-26 19:40:40 +020023#include <proto/log.h>
Willy Tarreaua84d3742007-05-07 00:36:48 +020024
Willy Tarreaua9802632008-07-25 19:13:19 +020025/* The capabilities of filtering hooks describe the type of information
26 * available to each of them.
27 */
28const unsigned int filt_cap[] = {
29 [ACL_HOOK_REQ_FE_TCP] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY,
30 [ACL_HOOK_REQ_FE_TCP_CONTENT] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY,
31 [ACL_HOOK_REQ_FE_HTTP_IN] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
32 [ACL_HOOK_REQ_FE_SWITCH] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
33 [ACL_HOOK_REQ_BE_TCP_CONTENT] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
34 [ACL_HOOK_REQ_BE_HTTP_IN] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
35 [ACL_HOOK_REQ_BE_SWITCH] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
36 [ACL_HOOK_REQ_FE_HTTP_OUT] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
37 [ACL_HOOK_REQ_BE_HTTP_OUT] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
38
39 [ACL_HOOK_RTR_BE_TCP_CONTENT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY,
40 [ACL_HOOK_RTR_BE_HTTP_IN] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
41 [ACL_HOOK_RTR_FE_TCP_CONTENT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
42 [ACL_HOOK_RTR_FE_HTTP_IN] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
43 [ACL_HOOK_RTR_BE_HTTP_OUT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
44 [ACL_HOOK_RTR_FE_HTTP_OUT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
45};
46
Willy Tarreaua84d3742007-05-07 00:36:48 +020047/* List head of all known ACL keywords */
48static struct acl_kw_list acl_keywords = {
49 .list = LIST_HEAD_INIT(acl_keywords.list)
50};
51
52
Willy Tarreaua5909832007-06-17 20:40:25 +020053/*
54 * These functions are only used for debugging complex configurations.
Willy Tarreaua84d3742007-05-07 00:36:48 +020055 */
Willy Tarreaua5909832007-06-17 20:40:25 +020056
Willy Tarreau58393e12008-07-20 10:39:22 +020057/* force TRUE to be returned at the fetch level */
Willy Tarreaua5909832007-06-17 20:40:25 +020058static int
Willy Tarreau58393e12008-07-20 10:39:22 +020059acl_fetch_true(struct proxy *px, struct session *l4, void *l7, int dir,
60 struct acl_expr *expr, struct acl_test *test)
Willy Tarreaua5909832007-06-17 20:40:25 +020061{
Willy Tarreau58393e12008-07-20 10:39:22 +020062 test->flags |= ACL_TEST_F_SET_RES_PASS;
Willy Tarreaua5909832007-06-17 20:40:25 +020063 return 1;
64}
65
Willy Tarreaub6fb4202008-07-20 11:18:28 +020066/* wait for more data as long as possible, then return TRUE. This should be
67 * used with content inspection.
68 */
69static int
70acl_fetch_wait_end(struct proxy *px, struct session *l4, void *l7, int dir,
71 struct acl_expr *expr, struct acl_test *test)
72{
73 if (dir & ACL_PARTIAL) {
74 test->flags |= ACL_TEST_F_MAY_CHANGE;
75 return 0;
76 }
77 test->flags |= ACL_TEST_F_SET_RES_PASS;
78 return 1;
79}
80
Willy Tarreau58393e12008-07-20 10:39:22 +020081/* force FALSE to be returned at the fetch level */
Willy Tarreaua5909832007-06-17 20:40:25 +020082static int
Willy Tarreau58393e12008-07-20 10:39:22 +020083acl_fetch_false(struct proxy *px, struct session *l4, void *l7, int dir,
84 struct acl_expr *expr, struct acl_test *test)
Willy Tarreaua84d3742007-05-07 00:36:48 +020085{
Willy Tarreau58393e12008-07-20 10:39:22 +020086 test->flags |= ACL_TEST_F_SET_RES_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +020087 return 1;
88}
89
Willy Tarreau58393e12008-07-20 10:39:22 +020090
91/*
92 * These functions are exported and may be used by any other component.
93 */
94
95/* ignore the current line */
96int acl_parse_nothing(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua5909832007-06-17 20:40:25 +020097{
Willy Tarreau58393e12008-07-20 10:39:22 +020098 return 1;
99}
100
101/* always fake a data retrieval */
102int acl_fetch_nothing(struct proxy *px, struct session *l4, void *l7, int dir,
103 struct acl_expr *expr, struct acl_test *test)
104{
105 return 1;
Willy Tarreaua5909832007-06-17 20:40:25 +0200106}
107
108/* always return false */
Willy Tarreau58393e12008-07-20 10:39:22 +0200109int acl_match_nothing(struct acl_test *test, struct acl_pattern *pattern)
Willy Tarreaua5909832007-06-17 20:40:25 +0200110{
Willy Tarreau11382812008-07-09 16:18:21 +0200111 return ACL_PAT_FAIL;
Willy Tarreaua5909832007-06-17 20:40:25 +0200112}
113
114
Willy Tarreaua84d3742007-05-07 00:36:48 +0200115/* NB: For two strings to be identical, it is required that their lengths match */
116int acl_match_str(struct acl_test *test, struct acl_pattern *pattern)
117{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200118 int icase;
119
Willy Tarreaua84d3742007-05-07 00:36:48 +0200120 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200121 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200122
123 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
124 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) == 0) ||
125 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) == 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200126 return ACL_PAT_PASS;
127 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200128}
129
Willy Tarreauf3d25982007-05-08 22:45:09 +0200130/* Executes a regex. It needs to change the data. If it is marked READ_ONLY
131 * then it will be allocated and duplicated in place so that others may use
132 * it later on. Note that this is embarrassing because we always try to avoid
133 * allocating memory at run time.
134 */
135int acl_match_reg(struct acl_test *test, struct acl_pattern *pattern)
136{
137 char old_char;
138 int ret;
139
140 if (unlikely(test->flags & ACL_TEST_F_READ_ONLY)) {
141 char *new_str;
142
143 new_str = calloc(1, test->len + 1);
144 if (!new_str)
Willy Tarreau11382812008-07-09 16:18:21 +0200145 return ACL_PAT_FAIL;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200146
147 memcpy(new_str, test->ptr, test->len);
148 new_str[test->len] = 0;
149 if (test->flags & ACL_TEST_F_MUST_FREE)
150 free(test->ptr);
151 test->ptr = new_str;
152 test->flags |= ACL_TEST_F_MUST_FREE;
153 test->flags &= ~ACL_TEST_F_READ_ONLY;
154 }
155
156 old_char = test->ptr[test->len];
157 test->ptr[test->len] = 0;
158
159 if (regexec(pattern->ptr.reg, test->ptr, 0, NULL, 0) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200160 ret = ACL_PAT_PASS;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200161 else
Willy Tarreau11382812008-07-09 16:18:21 +0200162 ret = ACL_PAT_FAIL;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200163
164 test->ptr[test->len] = old_char;
165 return ret;
166}
167
Willy Tarreaua84d3742007-05-07 00:36:48 +0200168/* Checks that the pattern matches the beginning of the tested string. */
169int acl_match_beg(struct acl_test *test, struct acl_pattern *pattern)
170{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200171 int icase;
172
Willy Tarreaua84d3742007-05-07 00:36:48 +0200173 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200174 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200175
176 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
177 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, pattern->len) != 0) ||
178 (!icase && strncmp(pattern->ptr.str, test->ptr, pattern->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200179 return ACL_PAT_FAIL;
180 return ACL_PAT_PASS;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200181}
182
183/* Checks that the pattern matches the end of the tested string. */
184int acl_match_end(struct acl_test *test, struct acl_pattern *pattern)
185{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200186 int icase;
187
Willy Tarreaua84d3742007-05-07 00:36:48 +0200188 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200189 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200190 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
191 if ((icase && strncasecmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0) ||
192 (!icase && strncmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200193 return ACL_PAT_FAIL;
194 return ACL_PAT_PASS;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200195}
196
197/* Checks that the pattern is included inside the tested string.
198 * NB: Suboptimal, should be rewritten using a Boyer-Moore method.
199 */
200int acl_match_sub(struct acl_test *test, struct acl_pattern *pattern)
201{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200202 int icase;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200203 char *end;
204 char *c;
205
206 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200207 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200208
209 end = test->ptr + test->len - pattern->len;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200210 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
211 if (icase) {
212 for (c = test->ptr; c <= end; c++) {
213 if (tolower(*c) != tolower(*pattern->ptr.str))
214 continue;
215 if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200216 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200217 }
218 } else {
219 for (c = test->ptr; c <= end; c++) {
220 if (*c != *pattern->ptr.str)
221 continue;
222 if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200223 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200224 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200225 }
Willy Tarreau11382812008-07-09 16:18:21 +0200226 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200227}
228
229/* This one is used by other real functions. It checks that the pattern is
230 * included inside the tested string, but enclosed between the specified
231 * delimitor, or a '/' or a '?' or at the beginning or end of the string.
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200232 * The delimitor is stripped at the beginning or end of the pattern.
Willy Tarreaua84d3742007-05-07 00:36:48 +0200233 */
234static int match_word(struct acl_test *test, struct acl_pattern *pattern, char delim)
235{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200236 int may_match, icase;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200237 char *c, *end;
238 char *ps;
239 int pl;
240
241 pl = pattern->len;
242 ps = pattern->ptr.str;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200243 while (pl > 0 && (*ps == delim || *ps == '/' || *ps == '?')) {
Willy Tarreaua84d3742007-05-07 00:36:48 +0200244 pl--;
245 ps++;
246 }
247
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200248 while (pl > 0 &&
249 (ps[pl - 1] == delim || ps[pl - 1] == '/' || ps[pl - 1] == '?'))
Willy Tarreaua84d3742007-05-07 00:36:48 +0200250 pl--;
251
252 if (pl > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200253 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200254
255 may_match = 1;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200256 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200257 end = test->ptr + test->len - pl;
258 for (c = test->ptr; c <= end; c++) {
259 if (*c == '/' || *c == delim || *c == '?') {
260 may_match = 1;
261 continue;
262 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200263
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200264 if (!may_match)
265 continue;
266
267 if (icase) {
268 if ((tolower(*c) == tolower(*ps)) &&
269 (strncasecmp(ps, c, pl) == 0) &&
270 (c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
Willy Tarreau11382812008-07-09 16:18:21 +0200271 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200272 } else {
273 if ((*c == *ps) &&
274 (strncmp(ps, c, pl) == 0) &&
275 (c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
Willy Tarreau11382812008-07-09 16:18:21 +0200276 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200277 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200278 may_match = 0;
279 }
Willy Tarreau11382812008-07-09 16:18:21 +0200280 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200281}
282
283/* Checks that the pattern is included inside the tested string, but enclosed
284 * between slashes or at the beginning or end of the string. Slashes at the
285 * beginning or end of the pattern are ignored.
286 */
287int acl_match_dir(struct acl_test *test, struct acl_pattern *pattern)
288{
289 return match_word(test, pattern, '/');
290}
291
292/* Checks that the pattern is included inside the tested string, but enclosed
293 * between dots or at the beginning or end of the string. Dots at the beginning
294 * or end of the pattern are ignored.
295 */
296int acl_match_dom(struct acl_test *test, struct acl_pattern *pattern)
297{
298 return match_word(test, pattern, '.');
299}
300
301/* Checks that the integer in <test> is included between min and max */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200302int acl_match_int(struct acl_test *test, struct acl_pattern *pattern)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200303{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200304 if ((!pattern->val.range.min_set || pattern->val.range.min <= test->i) &&
305 (!pattern->val.range.max_set || test->i <= pattern->val.range.max))
Willy Tarreau11382812008-07-09 16:18:21 +0200306 return ACL_PAT_PASS;
307 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200308}
309
Willy Tarreaua67fad92007-05-08 19:50:09 +0200310int acl_match_ip(struct acl_test *test, struct acl_pattern *pattern)
311{
312 struct in_addr *s;
313
314 if (test->i != AF_INET)
Willy Tarreau11382812008-07-09 16:18:21 +0200315 return ACL_PAT_FAIL;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200316
317 s = (void *)test->ptr;
318 if (((s->s_addr ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200319 return ACL_PAT_PASS;
320 return ACL_PAT_FAIL;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200321}
322
Willy Tarreaua84d3742007-05-07 00:36:48 +0200323/* Parse a string. It is allocated and duplicated. */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200324int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200325{
326 int len;
327
Willy Tarreauae8b7962007-06-09 23:10:04 +0200328 len = strlen(*text);
329 pattern->ptr.str = strdup(*text);
Willy Tarreaua84d3742007-05-07 00:36:48 +0200330 if (!pattern->ptr.str)
331 return 0;
332 pattern->len = len;
333 return 1;
334}
335
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100336/* Parse and concatenate all further strings into one. */
337int
338acl_parse_strcat(const char **text, struct acl_pattern *pattern, int *opaque)
339{
340
341 int len = 0, i;
342 char *s;
343
344 for (i = 0; *text[i]; i++)
345 len += strlen(text[i])+1;
346
347 pattern->ptr.str = s = calloc(1, len);
348 if (!pattern->ptr.str)
349 return 0;
350
351 for (i = 0; *text[i]; i++)
352 s += sprintf(s, i?" %s":"%s", text[i]);
353
354 pattern->len = len;
355
356 return i;
357}
358
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200359/* Free data allocated by acl_parse_reg */
360static void acl_free_reg(void *ptr) {
361
362 regfree((regex_t *)ptr);
363}
364
Willy Tarreauf3d25982007-05-08 22:45:09 +0200365/* Parse a regex. It is allocated. */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200366int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreauf3d25982007-05-08 22:45:09 +0200367{
368 regex_t *preg;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200369 int icase;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200370
371 preg = calloc(1, sizeof(regex_t));
372
373 if (!preg)
374 return 0;
375
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200376 icase = (pattern->flags & ACL_PAT_F_IGNORE_CASE) ? REG_ICASE : 0;
377 if (regcomp(preg, *text, REG_EXTENDED | REG_NOSUB | icase) != 0) {
Willy Tarreauf3d25982007-05-08 22:45:09 +0200378 free(preg);
379 return 0;
380 }
381
382 pattern->ptr.reg = preg;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200383 pattern->freeptrbuf = &acl_free_reg;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200384 return 1;
385}
386
Willy Tarreauae8b7962007-06-09 23:10:04 +0200387/* Parse a range of positive integers delimited by either ':' or '-'. If only
388 * one integer is read, it is set as both min and max. An operator may be
389 * specified as the prefix, among this list of 5 :
390 *
391 * 0:eq, 1:gt, 2:ge, 3:lt, 4:le
392 *
393 * The default operator is "eq". It supports range matching. Ranges are
394 * rejected for other operators. The operator may be changed at any time.
395 * The operator is stored in the 'opaque' argument.
396 *
Willy Tarreaua84d3742007-05-07 00:36:48 +0200397 */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200398int acl_parse_int(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200399{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200400 signed long long i;
401 unsigned int j, last, skip = 0;
402 const char *ptr = *text;
403
404
Willy Tarreau8f8e6452007-06-17 21:51:38 +0200405 while (!isdigit((unsigned char)*ptr)) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200406 if (strcmp(ptr, "eq") == 0) *opaque = 0;
407 else if (strcmp(ptr, "gt") == 0) *opaque = 1;
408 else if (strcmp(ptr, "ge") == 0) *opaque = 2;
409 else if (strcmp(ptr, "lt") == 0) *opaque = 3;
410 else if (strcmp(ptr, "le") == 0) *opaque = 4;
411 else
412 return 0;
413
414 skip++;
415 ptr = text[skip];
416 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200417
418 last = i = 0;
419 while (1) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200420 j = *ptr++;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200421 if ((j == '-' || j == ':') && !last) {
422 last++;
423 pattern->val.range.min = i;
424 i = 0;
425 continue;
426 }
427 j -= '0';
428 if (j > 9)
429 // also catches the terminating zero
430 break;
431 i *= 10;
432 i += j;
433 }
Willy Tarreauae8b7962007-06-09 23:10:04 +0200434
435 if (last && *opaque >= 1 && *opaque <= 4)
436 /* having a range with a min or a max is absurd */
437 return 0;
438
Willy Tarreaua84d3742007-05-07 00:36:48 +0200439 if (!last)
440 pattern->val.range.min = i;
441 pattern->val.range.max = i;
Willy Tarreauae8b7962007-06-09 23:10:04 +0200442
443 switch (*opaque) {
444 case 0: /* eq */
445 pattern->val.range.min_set = 1;
446 pattern->val.range.max_set = 1;
447 break;
448 case 1: /* gt */
449 pattern->val.range.min++; /* gt = ge + 1 */
450 case 2: /* ge */
451 pattern->val.range.min_set = 1;
452 pattern->val.range.max_set = 0;
453 break;
454 case 3: /* lt */
455 pattern->val.range.max--; /* lt = le - 1 */
456 case 4: /* le */
457 pattern->val.range.min_set = 0;
458 pattern->val.range.max_set = 1;
459 break;
460 }
461 return skip + 1;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200462}
463
Willy Tarreau4a26d2f2008-07-15 16:05:33 +0200464/* Parse a range of positive 2-component versions delimited by either ':' or
465 * '-'. The version consists in a major and a minor, both of which must be
466 * smaller than 65536, because internally they will be represented as a 32-bit
467 * integer.
468 * If only one version is read, it is set as both min and max. Just like for
469 * pure integers, an operator may be specified as the prefix, among this list
470 * of 5 :
471 *
472 * 0:eq, 1:gt, 2:ge, 3:lt, 4:le
473 *
474 * The default operator is "eq". It supports range matching. Ranges are
475 * rejected for other operators. The operator may be changed at any time.
476 * The operator is stored in the 'opaque' argument. This allows constructs
477 * such as the following one :
478 *
479 * acl obsolete_ssl ssl_req_proto lt 3
480 * acl unsupported_ssl ssl_req_proto gt 3.1
481 * acl valid_ssl ssl_req_proto 3.0-3.1
482 *
483 */
484int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, int *opaque)
485{
486 signed long long i;
487 unsigned int j, last, skip = 0;
488 const char *ptr = *text;
489
490
491 while (!isdigit((unsigned char)*ptr)) {
492 if (strcmp(ptr, "eq") == 0) *opaque = 0;
493 else if (strcmp(ptr, "gt") == 0) *opaque = 1;
494 else if (strcmp(ptr, "ge") == 0) *opaque = 2;
495 else if (strcmp(ptr, "lt") == 0) *opaque = 3;
496 else if (strcmp(ptr, "le") == 0) *opaque = 4;
497 else
498 return 0;
499
500 skip++;
501 ptr = text[skip];
502 }
503
504 last = i = 0;
505 while (1) {
506 j = *ptr++;
507 if (j == '.') {
508 /* minor part */
509 if (i >= 65536)
510 return 0;
511 i <<= 16;
512 continue;
513 }
514 if ((j == '-' || j == ':') && !last) {
515 last++;
516 if (i < 65536)
517 i <<= 16;
518 pattern->val.range.min = i;
519 i = 0;
520 continue;
521 }
522 j -= '0';
523 if (j > 9)
524 // also catches the terminating zero
525 break;
526 i = (i & 0xFFFF0000) + (i & 0xFFFF) * 10;
527 i += j;
528 }
529
530 /* if we only got a major version, let's shift it now */
531 if (i < 65536)
532 i <<= 16;
533
534 if (last && *opaque >= 1 && *opaque <= 4)
535 /* having a range with a min or a max is absurd */
536 return 0;
537
538 if (!last)
539 pattern->val.range.min = i;
540 pattern->val.range.max = i;
541
542 switch (*opaque) {
543 case 0: /* eq */
544 pattern->val.range.min_set = 1;
545 pattern->val.range.max_set = 1;
546 break;
547 case 1: /* gt */
548 pattern->val.range.min++; /* gt = ge + 1 */
549 case 2: /* ge */
550 pattern->val.range.min_set = 1;
551 pattern->val.range.max_set = 0;
552 break;
553 case 3: /* lt */
554 pattern->val.range.max--; /* lt = le - 1 */
555 case 4: /* le */
556 pattern->val.range.min_set = 0;
557 pattern->val.range.max_set = 1;
558 break;
559 }
560 return skip + 1;
561}
562
Willy Tarreaua67fad92007-05-08 19:50:09 +0200563/* Parse an IP address and an optional mask in the form addr[/mask].
564 * The addr may either be an IPv4 address or a hostname. The mask
565 * may either be a dotted mask or a number of bits. Returns 1 if OK,
566 * otherwise 0.
567 */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200568int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua67fad92007-05-08 19:50:09 +0200569{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200570 if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask))
571 return 1;
572 else
573 return 0;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200574}
575
Willy Tarreaua84d3742007-05-07 00:36:48 +0200576/*
577 * Registers the ACL keyword list <kwl> as a list of valid keywords for next
578 * parsing sessions.
579 */
580void acl_register_keywords(struct acl_kw_list *kwl)
581{
582 LIST_ADDQ(&acl_keywords.list, &kwl->list);
583}
584
585/*
586 * Unregisters the ACL keyword list <kwl> from the list of valid keywords.
587 */
588void acl_unregister_keywords(struct acl_kw_list *kwl)
589{
590 LIST_DEL(&kwl->list);
591 LIST_INIT(&kwl->list);
592}
593
594/* Return a pointer to the ACL <name> within the list starting at <head>, or
595 * NULL if not found.
596 */
597struct acl *find_acl_by_name(const char *name, struct list *head)
598{
599 struct acl *acl;
600 list_for_each_entry(acl, head, list) {
601 if (strcmp(acl->name, name) == 0)
602 return acl;
603 }
604 return NULL;
605}
606
607/* Return a pointer to the ACL keyword <kw>, or NULL if not found. Note that if
608 * <kw> contains an opening parenthesis, only the left part of it is checked.
609 */
610struct acl_keyword *find_acl_kw(const char *kw)
611{
612 int index;
613 const char *kwend;
614 struct acl_kw_list *kwl;
615
616 kwend = strchr(kw, '(');
617 if (!kwend)
618 kwend = kw + strlen(kw);
619
620 list_for_each_entry(kwl, &acl_keywords.list, list) {
621 for (index = 0; kwl->kw[index].kw != NULL; index++) {
622 if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
623 kwl->kw[index].kw[kwend-kw] == 0)
624 return &kwl->kw[index];
625 }
626 }
627 return NULL;
628}
629
630static void free_pattern(struct acl_pattern *pat)
631{
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200632
633 if (pat->ptr.ptr) {
634 if (pat->freeptrbuf)
635 pat->freeptrbuf(pat->ptr.ptr);
636
Willy Tarreaua84d3742007-05-07 00:36:48 +0200637 free(pat->ptr.ptr);
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200638 }
639
Willy Tarreaua84d3742007-05-07 00:36:48 +0200640 free(pat);
641}
642
643static void free_pattern_list(struct list *head)
644{
645 struct acl_pattern *pat, *tmp;
646 list_for_each_entry_safe(pat, tmp, head, list)
647 free_pattern(pat);
648}
649
650static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
651{
652 free_pattern_list(&expr->patterns);
653 LIST_INIT(&expr->patterns);
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100654 if (expr->arg_len && expr->arg.str)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200655 free(expr->arg.str);
656 expr->kw->use_cnt--;
657 return expr;
658}
659
660/* Parse an ACL expression starting at <args>[0], and return it.
661 * Right now, the only accepted syntax is :
662 * <subject> [<value>...]
663 */
664struct acl_expr *parse_acl_expr(const char **args)
665{
666 __label__ out_return, out_free_expr, out_free_pattern;
667 struct acl_expr *expr;
668 struct acl_keyword *aclkw;
669 struct acl_pattern *pattern;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200670 int opaque, patflags;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200671 const char *arg;
672
673 aclkw = find_acl_kw(args[0]);
674 if (!aclkw || !aclkw->parse)
675 goto out_return;
676
677 expr = (struct acl_expr *)calloc(1, sizeof(*expr));
678 if (!expr)
679 goto out_return;
680
681 expr->kw = aclkw;
682 aclkw->use_cnt++;
683 LIST_INIT(&expr->patterns);
684 expr->arg.str = NULL;
Willy Tarreaubb768912007-06-10 11:17:01 +0200685 expr->arg_len = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200686
687 arg = strchr(args[0], '(');
688 if (arg != NULL) {
689 char *end, *arg2;
690 /* there is an argument in the form "subject(arg)" */
691 arg++;
692 end = strchr(arg, ')');
693 if (!end)
694 goto out_free_expr;
Willy Tarreauac778f52010-01-26 19:02:46 +0100695 arg2 = my_strndup(arg, end - arg);
Willy Tarreau1edb1442010-01-27 20:13:38 +0100696 if (!arg2)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200697 goto out_free_expr;
Willy Tarreaubb768912007-06-10 11:17:01 +0200698 expr->arg_len = end - arg;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200699 expr->arg.str = arg2;
700 }
701
Willy Tarreaua84d3742007-05-07 00:36:48 +0200702 args++;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200703
704 /* check for options before patterns. Supported options are :
705 * -i : ignore case for all patterns by default
706 * -f : read patterns from those files
707 * -- : everything after this is not an option
708 */
709 patflags = 0;
710 while (**args == '-') {
711 if ((*args)[1] == 'i')
712 patflags |= ACL_PAT_F_IGNORE_CASE;
713 else if ((*args)[1] == 'f')
714 patflags |= ACL_PAT_F_FROM_FILE;
715 else if ((*args)[1] == '-') {
716 args++;
717 break;
718 }
719 else
720 break;
721 args++;
722 }
723
724 /* now parse all patterns */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200725 opaque = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200726 while (**args) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200727 int ret;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200728 pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
729 if (!pattern)
730 goto out_free_expr;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200731 pattern->flags = patflags;
732
Willy Tarreauae8b7962007-06-09 23:10:04 +0200733 ret = aclkw->parse(args, pattern, &opaque);
734 if (!ret)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200735 goto out_free_pattern;
736 LIST_ADDQ(&expr->patterns, &pattern->list);
Willy Tarreauae8b7962007-06-09 23:10:04 +0200737 args += ret;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200738 }
739
740 return expr;
741
742 out_free_pattern:
743 free_pattern(pattern);
744 out_free_expr:
745 prune_acl_expr(expr);
746 free(expr);
747 out_return:
748 return NULL;
749}
750
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +0200751/* Purge everything in the acl <acl>, then return <acl>. */
752struct acl *prune_acl(struct acl *acl) {
753
754 struct acl_expr *expr, *exprb;
755
756 free(acl->name);
757
758 list_for_each_entry_safe(expr, exprb, &acl->expr, list) {
759 LIST_DEL(&expr->list);
760 prune_acl_expr(expr);
761 free(expr);
762 }
763
764 return acl;
765}
766
Willy Tarreaua84d3742007-05-07 00:36:48 +0200767/* Parse an ACL with the name starting at <args>[0], and with a list of already
768 * known ACLs in <acl>. If the ACL was not in the list, it will be added.
769 * A pointer to that ACL is returned.
770 *
771 * args syntax: <aclname> <acl_expr>
772 */
773struct acl *parse_acl(const char **args, struct list *known_acl)
774{
775 __label__ out_return, out_free_acl_expr, out_free_name;
776 struct acl *cur_acl;
777 struct acl_expr *acl_expr;
778 char *name;
779
Willy Tarreau2e74c3f2007-12-02 18:45:09 +0100780 if (invalid_char(*args))
781 goto out_return;
782
Willy Tarreaua84d3742007-05-07 00:36:48 +0200783 acl_expr = parse_acl_expr(args + 1);
784 if (!acl_expr)
785 goto out_return;
786
Willy Tarreau404e8ab2009-07-26 19:40:40 +0200787 /* Check for args beginning with an opening parenthesis just after the
788 * subject, as this is almost certainly a typo. Right now we can only
789 * emit a warning, so let's do so.
790 */
Krzysztof Piotr Oledzki4cdd8312009-10-05 00:23:35 +0200791 if (!strchr(args[1], '(') && *args[2] == '(')
Willy Tarreau404e8ab2009-07-26 19:40:40 +0200792 Warning("parsing acl '%s' :\n"
793 " matching '%s' for pattern '%s' is likely a mistake and probably\n"
794 " not what you want. Maybe you need to remove the extraneous space before '('.\n"
795 " If you are really sure this is not an error, please insert '--' between the\n"
796 " match and the pattern to make this warning message disappear.\n",
797 args[0], args[1], args[2]);
798
Willy Tarreaua84d3742007-05-07 00:36:48 +0200799 cur_acl = find_acl_by_name(args[0], known_acl);
800 if (!cur_acl) {
801 name = strdup(args[0]);
802 if (!name)
803 goto out_free_acl_expr;
804 cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
805 if (cur_acl == NULL)
806 goto out_free_name;
807
808 LIST_INIT(&cur_acl->expr);
809 LIST_ADDQ(known_acl, &cur_acl->list);
810 cur_acl->name = name;
811 }
812
Willy Tarreaua9802632008-07-25 19:13:19 +0200813 cur_acl->requires |= acl_expr->kw->requires;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200814 LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
815 return cur_acl;
816
817 out_free_name:
818 free(name);
819 out_free_acl_expr:
820 prune_acl_expr(acl_expr);
821 free(acl_expr);
822 out_return:
823 return NULL;
824}
825
Willy Tarreau16fbe822007-06-17 11:54:31 +0200826/* Some useful ACLs provided by default. Only those used are allocated. */
827
828const struct {
829 const char *name;
830 const char *expr[4]; /* put enough for longest expression */
831} default_acl_list[] = {
Willy Tarreau58393e12008-07-20 10:39:22 +0200832 { .name = "TRUE", .expr = {"always_true",""}},
833 { .name = "FALSE", .expr = {"always_false",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +0200834 { .name = "LOCALHOST", .expr = {"src","127.0.0.1/8",""}},
Willy Tarreau2492d5b2009-07-11 00:06:00 +0200835 { .name = "HTTP", .expr = {"req_proto_http",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +0200836 { .name = "HTTP_1.0", .expr = {"req_ver","1.0",""}},
837 { .name = "HTTP_1.1", .expr = {"req_ver","1.1",""}},
838 { .name = "METH_CONNECT", .expr = {"method","CONNECT",""}},
839 { .name = "METH_GET", .expr = {"method","GET","HEAD",""}},
840 { .name = "METH_HEAD", .expr = {"method","HEAD",""}},
841 { .name = "METH_OPTIONS", .expr = {"method","OPTIONS",""}},
842 { .name = "METH_POST", .expr = {"method","POST",""}},
843 { .name = "METH_TRACE", .expr = {"method","TRACE",""}},
844 { .name = "HTTP_URL_ABS", .expr = {"url_reg","^[^/:]*://",""}},
845 { .name = "HTTP_URL_SLASH", .expr = {"url_beg","/",""}},
846 { .name = "HTTP_URL_STAR", .expr = {"url","*",""}},
847 { .name = "HTTP_CONTENT", .expr = {"hdr_val(content-length)","gt","0",""}},
Emeric Brunbede3d02009-06-30 17:54:00 +0200848 { .name = "RDP_COOKIE", .expr = {"req_rdp_cookie_cnt","gt","0",""}},
Willy Tarreauc6317702008-07-20 09:29:50 +0200849 { .name = "REQ_CONTENT", .expr = {"req_len","gt","0",""}},
Willy Tarreaub6fb4202008-07-20 11:18:28 +0200850 { .name = "WAIT_END", .expr = {"wait_end",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +0200851 { .name = NULL, .expr = {""}}
852};
853
854/* Find a default ACL from the default_acl list, compile it and return it.
855 * If the ACL is not found, NULL is returned. In theory, it cannot fail,
856 * except when default ACLs are broken, in which case it will return NULL.
857 * If <known_acl> is not NULL, the ACL will be queued at its tail.
858 */
859struct acl *find_acl_default(const char *acl_name, struct list *known_acl)
860{
861 __label__ out_return, out_free_acl_expr, out_free_name;
862 struct acl *cur_acl;
863 struct acl_expr *acl_expr;
864 char *name;
865 int index;
866
867 for (index = 0; default_acl_list[index].name != NULL; index++) {
868 if (strcmp(acl_name, default_acl_list[index].name) == 0)
869 break;
870 }
871
872 if (default_acl_list[index].name == NULL)
873 return NULL;
874
875 acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr);
876 if (!acl_expr)
877 goto out_return;
878
879 name = strdup(acl_name);
880 if (!name)
881 goto out_free_acl_expr;
882 cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
883 if (cur_acl == NULL)
884 goto out_free_name;
885
886 cur_acl->name = name;
Willy Tarreaua55b7dc2009-07-12 09:21:30 +0200887 cur_acl->requires |= acl_expr->kw->requires;
Willy Tarreau16fbe822007-06-17 11:54:31 +0200888 LIST_INIT(&cur_acl->expr);
889 LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
890 if (known_acl)
891 LIST_ADDQ(known_acl, &cur_acl->list);
892
893 return cur_acl;
894
895 out_free_name:
896 free(name);
897 out_free_acl_expr:
898 prune_acl_expr(acl_expr);
899 free(acl_expr);
900 out_return:
901 return NULL;
902}
Willy Tarreaua84d3742007-05-07 00:36:48 +0200903
904/* Purge everything in the acl_cond <cond>, then return <cond>. */
905struct acl_cond *prune_acl_cond(struct acl_cond *cond)
906{
907 struct acl_term_suite *suite, *tmp_suite;
908 struct acl_term *term, *tmp_term;
909
910 /* iterate through all term suites and free all terms and all suites */
911 list_for_each_entry_safe(suite, tmp_suite, &cond->suites, list) {
912 list_for_each_entry_safe(term, tmp_term, &suite->terms, list)
913 free(term);
914 free(suite);
915 }
916 return cond;
917}
918
919/* Parse an ACL condition starting at <args>[0], relying on a list of already
920 * known ACLs passed in <known_acl>. The new condition is returned (or NULL in
921 * case of low memory). Supports multiple conditions separated by "or".
922 */
923struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol)
924{
925 __label__ out_return, out_free_suite, out_free_term;
Willy Tarreau74b98a82007-06-16 19:35:18 +0200926 int arg, neg;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200927 const char *word;
928 struct acl *cur_acl;
929 struct acl_term *cur_term;
930 struct acl_term_suite *cur_suite;
931 struct acl_cond *cond;
932
933 cond = (struct acl_cond *)calloc(1, sizeof(*cond));
934 if (cond == NULL)
935 goto out_return;
936
937 LIST_INIT(&cond->list);
938 LIST_INIT(&cond->suites);
939 cond->pol = pol;
940
941 cur_suite = NULL;
Willy Tarreau74b98a82007-06-16 19:35:18 +0200942 neg = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200943 for (arg = 0; *args[arg]; arg++) {
944 word = args[arg];
945
946 /* remove as many exclamation marks as we can */
947 while (*word == '!') {
948 neg = !neg;
949 word++;
950 }
951
952 /* an empty word is allowed because we cannot force the user to
953 * always think about not leaving exclamation marks alone.
954 */
955 if (!*word)
956 continue;
957
Willy Tarreau16fbe822007-06-17 11:54:31 +0200958 if (strcasecmp(word, "or") == 0 || strcmp(word, "||") == 0) {
Willy Tarreaua84d3742007-05-07 00:36:48 +0200959 /* new term suite */
960 cur_suite = NULL;
961 neg = 0;
962 continue;
963 }
964
Willy Tarreau16fbe822007-06-17 11:54:31 +0200965 /* search for <word> in the known ACL names. If we do not find
966 * it, let's look for it in the default ACLs, and if found, add
967 * it to the list of ACLs of this proxy. This makes it possible
968 * to override them.
969 */
Willy Tarreaua84d3742007-05-07 00:36:48 +0200970 cur_acl = find_acl_by_name(word, known_acl);
Willy Tarreau16fbe822007-06-17 11:54:31 +0200971 if (cur_acl == NULL) {
972 cur_acl = find_acl_default(word, known_acl);
973 if (cur_acl == NULL)
974 goto out_free_suite;
975 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200976
977 cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term));
978 if (cur_term == NULL)
979 goto out_free_suite;
980
981 cur_term->acl = cur_acl;
982 cur_term->neg = neg;
Willy Tarreaua9802632008-07-25 19:13:19 +0200983 cond->requires |= cur_acl->requires;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200984
985 if (!cur_suite) {
986 cur_suite = (struct acl_term_suite *)calloc(1, sizeof(*cur_suite));
987 if (cur_term == NULL)
988 goto out_free_term;
989 LIST_INIT(&cur_suite->terms);
990 LIST_ADDQ(&cond->suites, &cur_suite->list);
991 }
992 LIST_ADDQ(&cur_suite->terms, &cur_term->list);
Willy Tarreau74b98a82007-06-16 19:35:18 +0200993 neg = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200994 }
995
996 return cond;
997
998 out_free_term:
999 free(cur_term);
1000 out_free_suite:
1001 prune_acl_cond(cond);
1002 free(cond);
1003 out_return:
1004 return NULL;
1005}
1006
Willy Tarreau2bbba412010-01-28 16:48:33 +01001007/* Builds an ACL condition starting at the if/unless keyword. The complete
1008 * condition is returned. NULL is returned in case of error or if the first
1009 * word is neither "if" nor "unless". It automatically sets the file name and
1010 * the line number in the condition for better error reporting, and adds the
1011 * ACL requirements to the proxy's acl_requires.
1012 */
1013struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args)
1014{
1015 int pol = ACL_COND_NONE;
1016 struct acl_cond *cond = NULL;
1017
1018 if (!strcmp(*args, "if")) {
1019 pol = ACL_COND_IF;
1020 args++;
1021 }
1022 else if (!strcmp(*args, "unless")) {
1023 pol = ACL_COND_UNLESS;
1024 args++;
1025 }
1026 else
1027 return NULL;
1028
1029 cond = parse_acl_cond(args, &px->acl, pol);
1030 if (!cond)
1031 return NULL;
1032
1033 cond->file = file;
1034 cond->line = line;
1035 px->acl_requires |= cond->requires;
1036
1037 return cond;
1038}
1039
Willy Tarreau11382812008-07-09 16:18:21 +02001040/* Execute condition <cond> and return either ACL_PAT_FAIL, ACL_PAT_MISS or
Willy Tarreaub6866442008-07-14 23:54:42 +02001041 * ACL_PAT_PASS depending on the test results. ACL_PAT_MISS may only be
1042 * returned if <dir> contains ACL_PARTIAL, indicating that incomplete data
1043 * is being examined.
1044 * This function only computes the condition, it does not apply the polarity
1045 * required by IF/UNLESS, it's up to the caller to do this using something like
1046 * this :
Willy Tarreau11382812008-07-09 16:18:21 +02001047 *
1048 * res = acl_pass(res);
Willy Tarreaub6866442008-07-14 23:54:42 +02001049 * if (res == ACL_PAT_MISS)
1050 * return 0;
Willy Tarreau11382812008-07-09 16:18:21 +02001051 * if (cond->pol == ACL_COND_UNLESS)
1052 * res = !res;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001053 */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001054int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, void *l7, int dir)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001055{
1056 __label__ fetch_next;
1057 struct acl_term_suite *suite;
1058 struct acl_term *term;
1059 struct acl_expr *expr;
1060 struct acl *acl;
1061 struct acl_pattern *pattern;
1062 struct acl_test test;
Willy Tarreau11382812008-07-09 16:18:21 +02001063 int acl_res, suite_res, cond_res;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001064
Willy Tarreau11382812008-07-09 16:18:21 +02001065 /* We're doing a logical OR between conditions so we initialize to FAIL.
1066 * The MISS status is propagated down from the suites.
1067 */
Willy Tarreaua84d3742007-05-07 00:36:48 +02001068 cond_res = ACL_PAT_FAIL;
1069 list_for_each_entry(suite, &cond->suites, list) {
Willy Tarreau11382812008-07-09 16:18:21 +02001070 /* Evaluate condition suite <suite>. We stop at the first term
1071 * which returns ACL_PAT_FAIL. The MISS status is still propagated
1072 * in case of uncertainty in the result.
Willy Tarreaua84d3742007-05-07 00:36:48 +02001073 */
1074
1075 /* we're doing a logical AND between terms, so we must set the
1076 * initial value to PASS.
1077 */
1078 suite_res = ACL_PAT_PASS;
1079 list_for_each_entry(term, &suite->terms, list) {
1080 acl = term->acl;
1081
1082 /* FIXME: use cache !
1083 * check acl->cache_idx for this.
1084 */
1085
1086 /* ACL result not cached. Let's scan all the expressions
1087 * and use the first one to match.
1088 */
1089 acl_res = ACL_PAT_FAIL;
1090 list_for_each_entry(expr, &acl->expr, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001091 /* we need to reset context and flags */
1092 memset(&test, 0, sizeof(test));
Willy Tarreaua84d3742007-05-07 00:36:48 +02001093 fetch_next:
Willy Tarreaub6866442008-07-14 23:54:42 +02001094 if (!expr->kw->fetch(px, l4, l7, dir, expr, &test)) {
1095 /* maybe we could not fetch because of missing data */
1096 if (test.flags & ACL_TEST_F_MAY_CHANGE && dir & ACL_PARTIAL)
1097 acl_res |= ACL_PAT_MISS;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001098 continue;
Willy Tarreaub6866442008-07-14 23:54:42 +02001099 }
Willy Tarreaua84d3742007-05-07 00:36:48 +02001100
Willy Tarreaua79534f2008-07-20 10:13:37 +02001101 if (test.flags & ACL_TEST_F_RES_SET) {
1102 if (test.flags & ACL_TEST_F_RES_PASS)
1103 acl_res |= ACL_PAT_PASS;
1104 else
1105 acl_res |= ACL_PAT_FAIL;
1106 }
1107 else {
1108 /* call the match() function for all tests on this value */
1109 list_for_each_entry(pattern, &expr->patterns, list) {
1110 acl_res |= expr->kw->match(&test, pattern);
1111 if (acl_res == ACL_PAT_PASS)
1112 break;
1113 }
Krzysztof Piotr Oledzkid7528e52010-01-29 17:55:53 +01001114
1115 if ((test.flags & ACL_TEST_F_NULL_MATCH) && LIST_ISEMPTY(&expr->patterns))
1116 acl_res |= expr->kw->match(&test, NULL);
Willy Tarreaua84d3742007-05-07 00:36:48 +02001117 }
1118 /*
Willy Tarreau11382812008-07-09 16:18:21 +02001119 * OK now acl_res holds the result of this expression
1120 * as one of ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
Willy Tarreaua84d3742007-05-07 00:36:48 +02001121 *
Willy Tarreau11382812008-07-09 16:18:21 +02001122 * Then if (!MISS) we can cache the result, and put
Willy Tarreaua84d3742007-05-07 00:36:48 +02001123 * (test.flags & ACL_TEST_F_VOLATILE) in the cache flags.
1124 *
1125 * FIXME: implement cache.
1126 *
1127 */
1128
1129 /* now we may have some cleanup to do */
1130 if (test.flags & ACL_TEST_F_MUST_FREE) {
1131 free(test.ptr);
1132 test.len = 0;
1133 }
1134
Willy Tarreau11382812008-07-09 16:18:21 +02001135 /* we're ORing these terms, so a single PASS is enough */
1136 if (acl_res == ACL_PAT_PASS)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001137 break;
1138
Willy Tarreaua84d3742007-05-07 00:36:48 +02001139 if (test.flags & ACL_TEST_F_FETCH_MORE)
1140 goto fetch_next;
Willy Tarreaub6866442008-07-14 23:54:42 +02001141
1142 /* sometimes we know the fetched data is subject to change
1143 * later and give another chance for a new match (eg: request
1144 * size, time, ...)
1145 */
1146 if (test.flags & ACL_TEST_F_MAY_CHANGE && dir & ACL_PARTIAL)
1147 acl_res |= ACL_PAT_MISS;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001148 }
1149 /*
1150 * Here we have the result of an ACL (cached or not).
1151 * ACLs are combined, negated or not, to form conditions.
1152 */
1153
Willy Tarreaua84d3742007-05-07 00:36:48 +02001154 if (term->neg)
Willy Tarreau11382812008-07-09 16:18:21 +02001155 acl_res = acl_neg(acl_res);
Willy Tarreaua84d3742007-05-07 00:36:48 +02001156
1157 suite_res &= acl_res;
Willy Tarreau11382812008-07-09 16:18:21 +02001158
1159 /* we're ANDing these terms, so a single FAIL is enough */
1160 if (suite_res == ACL_PAT_FAIL)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001161 break;
1162 }
1163 cond_res |= suite_res;
Willy Tarreau11382812008-07-09 16:18:21 +02001164
1165 /* we're ORing these terms, so a single PASS is enough */
1166 if (cond_res == ACL_PAT_PASS)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001167 break;
1168 }
Willy Tarreau11382812008-07-09 16:18:21 +02001169 return cond_res;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001170}
1171
1172
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001173/* Reports a pointer to the first ACL used in condition <cond> which requires
1174 * at least one of the USE_FLAGS in <require>. Returns NULL if none matches.
1175 * The construct is almost the same as for acl_exec_cond() since we're walking
1176 * down the ACL tree as well. It is important that the tree is really walked
1177 * through and never cached, because that way, this function can be used as a
1178 * late check.
1179 */
Willy Tarreauf1e98b82010-01-28 17:59:39 +01001180struct acl *cond_find_require(const struct acl_cond *cond, unsigned int require)
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001181{
1182 struct acl_term_suite *suite;
1183 struct acl_term *term;
1184 struct acl *acl;
1185
1186 list_for_each_entry(suite, &cond->suites, list) {
1187 list_for_each_entry(term, &suite->terms, list) {
1188 acl = term->acl;
1189 if (acl->requires & require)
1190 return acl;
1191 }
1192 }
1193 return NULL;
1194}
1195
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001196/*
1197 * Find targets for userlist and groups in acl. Function returns the number
1198 * of errors or OK if everything is fine.
1199 */
1200int
1201acl_find_targets(struct proxy *p)
1202{
1203
1204 struct acl *acl;
1205 struct acl_expr *expr;
1206 struct acl_pattern *pattern;
1207 struct userlist *ul;
1208 int cfgerr = 0;
1209
1210 list_for_each_entry(acl, &p->acl, list) {
1211 list_for_each_entry(expr, &acl->expr, list) {
1212 if (strstr(expr->kw->kw, "http_auth") == expr->kw->kw) {
1213
1214 if (!expr->arg.str || !*expr->arg.str) {
1215 Alert("proxy %s: acl %s %s(): missing userlist name.\n",
1216 p->id, acl->name, expr->kw->kw);
1217 cfgerr++;
1218 continue;
1219 }
1220
1221 ul = auth_find_userlist(expr->arg.str);
1222
1223 if (!ul) {
1224 Alert("proxy %s: acl %s %s(%s): unable to find userlist.\n",
1225 p->id, acl->name, expr->kw->kw, expr->arg.str);
1226 cfgerr++;
1227 continue;
1228 }
1229
1230 expr->arg_len = 0;
1231 expr->arg.ul = ul;
1232 }
1233
1234
1235 if (!strcmp(expr->kw->kw, "http_auth_group")) {
1236
1237 if (LIST_ISEMPTY(&expr->patterns)) {
1238 Alert("proxy %s: acl %s %s(): no groups specified.\n",
1239 p->id, acl->name, expr->kw->kw);
1240 cfgerr++;
1241 continue;
1242 }
1243
1244 list_for_each_entry(pattern, &expr->patterns, list) {
1245 pattern->val.group_mask = auth_resolve_groups(expr->arg.ul, pattern->ptr.str);
1246
1247 free(pattern->ptr.str);
1248 pattern->ptr.str = NULL;
1249 pattern->len = 0;
1250
1251 if (!pattern->val.group_mask) {
1252 Alert("proxy %s: acl %s %s(): invalid group(s).\n",
1253 p->id, acl->name, expr->kw->kw);
1254 cfgerr++;
1255 continue;
1256 }
1257 }
1258 }
1259 }
1260 }
1261
1262 return cfgerr;
1263}
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001264
Willy Tarreaua84d3742007-05-07 00:36:48 +02001265/************************************************************************/
1266/* All supported keywords must be declared here. */
1267/************************************************************************/
1268
1269/* Note: must not be declared <const> as its list will be overwritten */
1270static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02001271 { "always_true", acl_parse_nothing, acl_fetch_true, acl_match_nothing, ACL_USE_NOTHING },
1272 { "always_false", acl_parse_nothing, acl_fetch_false, acl_match_nothing, ACL_USE_NOTHING },
1273 { "wait_end", acl_parse_nothing, acl_fetch_wait_end, acl_match_nothing, ACL_USE_NOTHING },
Willy Tarreaua84d3742007-05-07 00:36:48 +02001274#if 0
1275 { "time", acl_parse_time, acl_fetch_time, acl_match_time },
1276#endif
1277 { NULL, NULL, NULL, NULL }
1278}};
1279
1280
1281__attribute__((constructor))
1282static void __acl_init(void)
1283{
1284 acl_register_keywords(&acl_kws);
1285}
1286
1287
1288/*
1289 * Local variables:
1290 * c-indent-level: 8
1291 * c-basic-offset: 8
1292 * End:
1293 */