blob: a4c61a039133d8128d985f45912b7132d7fe9b55 [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>
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +010020#include <common/uri_auth.h>
Willy Tarreaua84d3742007-05-07 00:36:48 +020021
Willy Tarreau2b5285d2010-05-09 23:45:24 +020022#include <types/global.h>
23
Willy Tarreaua84d3742007-05-07 00:36:48 +020024#include <proto/acl.h>
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +010025#include <proto/auth.h>
Willy Tarreau404e8ab2009-07-26 19:40:40 +020026#include <proto/log.h>
Willy Tarreau0b1cd942010-05-16 22:18:27 +020027#include <proto/proxy.h>
Willy Tarreaua84d3742007-05-07 00:36:48 +020028
Willy Tarreauc4262962010-05-10 23:42:40 +020029#include <ebsttree.h>
30
Willy Tarreaua9802632008-07-25 19:13:19 +020031/* The capabilities of filtering hooks describe the type of information
32 * available to each of them.
33 */
34const unsigned int filt_cap[] = {
35 [ACL_HOOK_REQ_FE_TCP] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY,
36 [ACL_HOOK_REQ_FE_TCP_CONTENT] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY,
37 [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,
38 [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,
39 [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,
40 [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,
41 [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,
42 [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,
43 [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,
44
45 [ACL_HOOK_RTR_BE_TCP_CONTENT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY,
46 [ACL_HOOK_RTR_BE_HTTP_IN] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
47 [ACL_HOOK_RTR_FE_TCP_CONTENT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
48 [ACL_HOOK_RTR_FE_HTTP_IN] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
49 [ACL_HOOK_RTR_BE_HTTP_OUT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
50 [ACL_HOOK_RTR_FE_HTTP_OUT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
51};
52
Willy Tarreaua84d3742007-05-07 00:36:48 +020053/* List head of all known ACL keywords */
54static struct acl_kw_list acl_keywords = {
55 .list = LIST_HEAD_INIT(acl_keywords.list)
56};
57
58
Willy Tarreaua5909832007-06-17 20:40:25 +020059/*
60 * These functions are only used for debugging complex configurations.
Willy Tarreaua84d3742007-05-07 00:36:48 +020061 */
Willy Tarreaua5909832007-06-17 20:40:25 +020062
Willy Tarreau58393e12008-07-20 10:39:22 +020063/* force TRUE to be returned at the fetch level */
Willy Tarreaua5909832007-06-17 20:40:25 +020064static int
Willy Tarreau58393e12008-07-20 10:39:22 +020065acl_fetch_true(struct proxy *px, struct session *l4, void *l7, int dir,
66 struct acl_expr *expr, struct acl_test *test)
Willy Tarreaua5909832007-06-17 20:40:25 +020067{
Willy Tarreau58393e12008-07-20 10:39:22 +020068 test->flags |= ACL_TEST_F_SET_RES_PASS;
Willy Tarreaua5909832007-06-17 20:40:25 +020069 return 1;
70}
71
Willy Tarreaub6fb4202008-07-20 11:18:28 +020072/* wait for more data as long as possible, then return TRUE. This should be
73 * used with content inspection.
74 */
75static int
76acl_fetch_wait_end(struct proxy *px, struct session *l4, void *l7, int dir,
77 struct acl_expr *expr, struct acl_test *test)
78{
79 if (dir & ACL_PARTIAL) {
80 test->flags |= ACL_TEST_F_MAY_CHANGE;
81 return 0;
82 }
83 test->flags |= ACL_TEST_F_SET_RES_PASS;
84 return 1;
85}
86
Willy Tarreau58393e12008-07-20 10:39:22 +020087/* force FALSE to be returned at the fetch level */
Willy Tarreaua5909832007-06-17 20:40:25 +020088static int
Willy Tarreau58393e12008-07-20 10:39:22 +020089acl_fetch_false(struct proxy *px, struct session *l4, void *l7, int dir,
90 struct acl_expr *expr, struct acl_test *test)
Willy Tarreaua84d3742007-05-07 00:36:48 +020091{
Willy Tarreau58393e12008-07-20 10:39:22 +020092 test->flags |= ACL_TEST_F_SET_RES_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +020093 return 1;
94}
95
Willy Tarreau58393e12008-07-20 10:39:22 +020096
97/*
98 * These functions are exported and may be used by any other component.
99 */
100
101/* ignore the current line */
102int acl_parse_nothing(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua5909832007-06-17 20:40:25 +0200103{
Willy Tarreau58393e12008-07-20 10:39:22 +0200104 return 1;
105}
106
107/* always fake a data retrieval */
108int acl_fetch_nothing(struct proxy *px, struct session *l4, void *l7, int dir,
109 struct acl_expr *expr, struct acl_test *test)
110{
111 return 1;
Willy Tarreaua5909832007-06-17 20:40:25 +0200112}
113
114/* always return false */
Willy Tarreau58393e12008-07-20 10:39:22 +0200115int acl_match_nothing(struct acl_test *test, struct acl_pattern *pattern)
Willy Tarreaua5909832007-06-17 20:40:25 +0200116{
Willy Tarreau11382812008-07-09 16:18:21 +0200117 return ACL_PAT_FAIL;
Willy Tarreaua5909832007-06-17 20:40:25 +0200118}
119
120
Willy Tarreaua84d3742007-05-07 00:36:48 +0200121/* NB: For two strings to be identical, it is required that their lengths match */
122int acl_match_str(struct acl_test *test, struct acl_pattern *pattern)
123{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200124 int icase;
125
Willy Tarreaua84d3742007-05-07 00:36:48 +0200126 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200127 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200128
129 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
130 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) == 0) ||
131 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) == 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200132 return ACL_PAT_PASS;
133 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200134}
135
Willy Tarreauc4262962010-05-10 23:42:40 +0200136/* Lookup a string in the expression's pattern tree. The node is returned if it
137 * exists, otherwise NULL.
138 */
139void *acl_lookup_str(struct acl_test *test, struct acl_expr *expr)
140{
141 /* data are stored in a tree */
142 struct ebmb_node *node;
143 char prev;
144
145 /* we may have to force a trailing zero on the test pattern */
146 prev = test->ptr[test->len];
147 if (prev)
148 test->ptr[test->len] = '\0';
149 node = ebst_lookup(&expr->pattern_tree, test->ptr);
150 if (prev)
151 test->ptr[test->len] = prev;
152 return node;
153}
154
Willy Tarreauf3d25982007-05-08 22:45:09 +0200155/* Executes a regex. It needs to change the data. If it is marked READ_ONLY
156 * then it will be allocated and duplicated in place so that others may use
157 * it later on. Note that this is embarrassing because we always try to avoid
158 * allocating memory at run time.
159 */
160int acl_match_reg(struct acl_test *test, struct acl_pattern *pattern)
161{
162 char old_char;
163 int ret;
164
165 if (unlikely(test->flags & ACL_TEST_F_READ_ONLY)) {
166 char *new_str;
167
168 new_str = calloc(1, test->len + 1);
169 if (!new_str)
Willy Tarreau11382812008-07-09 16:18:21 +0200170 return ACL_PAT_FAIL;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200171
172 memcpy(new_str, test->ptr, test->len);
173 new_str[test->len] = 0;
174 if (test->flags & ACL_TEST_F_MUST_FREE)
175 free(test->ptr);
176 test->ptr = new_str;
177 test->flags |= ACL_TEST_F_MUST_FREE;
178 test->flags &= ~ACL_TEST_F_READ_ONLY;
179 }
180
181 old_char = test->ptr[test->len];
182 test->ptr[test->len] = 0;
183
184 if (regexec(pattern->ptr.reg, test->ptr, 0, NULL, 0) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200185 ret = ACL_PAT_PASS;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200186 else
Willy Tarreau11382812008-07-09 16:18:21 +0200187 ret = ACL_PAT_FAIL;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200188
189 test->ptr[test->len] = old_char;
190 return ret;
191}
192
Willy Tarreaua84d3742007-05-07 00:36:48 +0200193/* Checks that the pattern matches the beginning of the tested string. */
194int acl_match_beg(struct acl_test *test, struct acl_pattern *pattern)
195{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200196 int icase;
197
Willy Tarreaua84d3742007-05-07 00:36:48 +0200198 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200199 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200200
201 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
202 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, pattern->len) != 0) ||
203 (!icase && strncmp(pattern->ptr.str, test->ptr, pattern->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200204 return ACL_PAT_FAIL;
205 return ACL_PAT_PASS;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200206}
207
208/* Checks that the pattern matches the end of the tested string. */
209int acl_match_end(struct acl_test *test, struct acl_pattern *pattern)
210{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200211 int icase;
212
Willy Tarreaua84d3742007-05-07 00:36:48 +0200213 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200214 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200215 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
216 if ((icase && strncasecmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0) ||
217 (!icase && strncmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200218 return ACL_PAT_FAIL;
219 return ACL_PAT_PASS;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200220}
221
222/* Checks that the pattern is included inside the tested string.
223 * NB: Suboptimal, should be rewritten using a Boyer-Moore method.
224 */
225int acl_match_sub(struct acl_test *test, struct acl_pattern *pattern)
226{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200227 int icase;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200228 char *end;
229 char *c;
230
231 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200232 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200233
234 end = test->ptr + test->len - pattern->len;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200235 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
236 if (icase) {
237 for (c = test->ptr; c <= end; c++) {
238 if (tolower(*c) != tolower(*pattern->ptr.str))
239 continue;
240 if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200241 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200242 }
243 } else {
244 for (c = test->ptr; c <= end; c++) {
245 if (*c != *pattern->ptr.str)
246 continue;
247 if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200248 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200249 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200250 }
Willy Tarreau11382812008-07-09 16:18:21 +0200251 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200252}
253
254/* This one is used by other real functions. It checks that the pattern is
255 * included inside the tested string, but enclosed between the specified
256 * delimitor, or a '/' or a '?' or at the beginning or end of the string.
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200257 * The delimitor is stripped at the beginning or end of the pattern.
Willy Tarreaua84d3742007-05-07 00:36:48 +0200258 */
259static int match_word(struct acl_test *test, struct acl_pattern *pattern, char delim)
260{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200261 int may_match, icase;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200262 char *c, *end;
263 char *ps;
264 int pl;
265
266 pl = pattern->len;
267 ps = pattern->ptr.str;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200268 while (pl > 0 && (*ps == delim || *ps == '/' || *ps == '?')) {
Willy Tarreaua84d3742007-05-07 00:36:48 +0200269 pl--;
270 ps++;
271 }
272
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200273 while (pl > 0 &&
274 (ps[pl - 1] == delim || ps[pl - 1] == '/' || ps[pl - 1] == '?'))
Willy Tarreaua84d3742007-05-07 00:36:48 +0200275 pl--;
276
277 if (pl > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200278 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200279
280 may_match = 1;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200281 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200282 end = test->ptr + test->len - pl;
283 for (c = test->ptr; c <= end; c++) {
284 if (*c == '/' || *c == delim || *c == '?') {
285 may_match = 1;
286 continue;
287 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200288
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200289 if (!may_match)
290 continue;
291
292 if (icase) {
293 if ((tolower(*c) == tolower(*ps)) &&
294 (strncasecmp(ps, c, pl) == 0) &&
295 (c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
Willy Tarreau11382812008-07-09 16:18:21 +0200296 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200297 } else {
298 if ((*c == *ps) &&
299 (strncmp(ps, c, pl) == 0) &&
300 (c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
Willy Tarreau11382812008-07-09 16:18:21 +0200301 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200302 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200303 may_match = 0;
304 }
Willy Tarreau11382812008-07-09 16:18:21 +0200305 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200306}
307
308/* Checks that the pattern is included inside the tested string, but enclosed
309 * between slashes or at the beginning or end of the string. Slashes at the
310 * beginning or end of the pattern are ignored.
311 */
312int acl_match_dir(struct acl_test *test, struct acl_pattern *pattern)
313{
314 return match_word(test, pattern, '/');
315}
316
317/* Checks that the pattern is included inside the tested string, but enclosed
318 * between dots or at the beginning or end of the string. Dots at the beginning
319 * or end of the pattern are ignored.
320 */
321int acl_match_dom(struct acl_test *test, struct acl_pattern *pattern)
322{
323 return match_word(test, pattern, '.');
324}
325
326/* Checks that the integer in <test> is included between min and max */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200327int acl_match_int(struct acl_test *test, struct acl_pattern *pattern)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200328{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200329 if ((!pattern->val.range.min_set || pattern->val.range.min <= test->i) &&
330 (!pattern->val.range.max_set || test->i <= pattern->val.range.max))
Willy Tarreau11382812008-07-09 16:18:21 +0200331 return ACL_PAT_PASS;
332 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200333}
334
Willy Tarreaua67fad92007-05-08 19:50:09 +0200335int acl_match_ip(struct acl_test *test, struct acl_pattern *pattern)
336{
337 struct in_addr *s;
338
339 if (test->i != AF_INET)
Willy Tarreau11382812008-07-09 16:18:21 +0200340 return ACL_PAT_FAIL;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200341
342 s = (void *)test->ptr;
343 if (((s->s_addr ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200344 return ACL_PAT_PASS;
345 return ACL_PAT_FAIL;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200346}
347
Willy Tarreaub337b532010-05-13 20:03:41 +0200348/* Lookup an IPv4 address in the expression's pattern tree using the longest
349 * match method. The node is returned if it exists, otherwise NULL.
350 */
351void *acl_lookup_ip(struct acl_test *test, struct acl_expr *expr)
352{
353 struct in_addr *s;
354
355 if (test->i != AF_INET)
356 return ACL_PAT_FAIL;
357
358 s = (void *)test->ptr;
359
360 return ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
361}
362
Willy Tarreaua84d3742007-05-07 00:36:48 +0200363/* Parse a string. It is allocated and duplicated. */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200364int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200365{
366 int len;
367
Willy Tarreauae8b7962007-06-09 23:10:04 +0200368 len = strlen(*text);
Willy Tarreauc4262962010-05-10 23:42:40 +0200369
370 if (pattern->flags & ACL_PAT_F_TREE_OK) {
371 /* we're allowed to put the data in a tree whose root is pointed
372 * to by val.tree.
373 */
374 struct ebmb_node *node;
375
376 node = calloc(1, sizeof(*node) + len + 1);
377 if (!node)
378 return 0;
379 memcpy(node->key, *text, len + 1);
380 if (ebst_insert(pattern->val.tree, node) != node)
381 free(node); /* was a duplicate */
382 pattern->flags |= ACL_PAT_F_TREE; /* this pattern now contains a tree */
383 return 1;
384 }
385
Willy Tarreauae8b7962007-06-09 23:10:04 +0200386 pattern->ptr.str = strdup(*text);
Willy Tarreaua84d3742007-05-07 00:36:48 +0200387 if (!pattern->ptr.str)
388 return 0;
389 pattern->len = len;
390 return 1;
391}
392
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100393/* Parse and concatenate all further strings into one. */
394int
395acl_parse_strcat(const char **text, struct acl_pattern *pattern, int *opaque)
396{
397
398 int len = 0, i;
399 char *s;
400
401 for (i = 0; *text[i]; i++)
402 len += strlen(text[i])+1;
403
404 pattern->ptr.str = s = calloc(1, len);
405 if (!pattern->ptr.str)
406 return 0;
407
408 for (i = 0; *text[i]; i++)
409 s += sprintf(s, i?" %s":"%s", text[i]);
410
411 pattern->len = len;
412
413 return i;
414}
415
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200416/* Free data allocated by acl_parse_reg */
417static void acl_free_reg(void *ptr) {
418
419 regfree((regex_t *)ptr);
420}
421
Willy Tarreauf3d25982007-05-08 22:45:09 +0200422/* Parse a regex. It is allocated. */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200423int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreauf3d25982007-05-08 22:45:09 +0200424{
425 regex_t *preg;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200426 int icase;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200427
428 preg = calloc(1, sizeof(regex_t));
429
430 if (!preg)
431 return 0;
432
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200433 icase = (pattern->flags & ACL_PAT_F_IGNORE_CASE) ? REG_ICASE : 0;
434 if (regcomp(preg, *text, REG_EXTENDED | REG_NOSUB | icase) != 0) {
Willy Tarreauf3d25982007-05-08 22:45:09 +0200435 free(preg);
436 return 0;
437 }
438
439 pattern->ptr.reg = preg;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200440 pattern->freeptrbuf = &acl_free_reg;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200441 return 1;
442}
443
Willy Tarreauae8b7962007-06-09 23:10:04 +0200444/* Parse a range of positive integers delimited by either ':' or '-'. If only
445 * one integer is read, it is set as both min and max. An operator may be
446 * specified as the prefix, among this list of 5 :
447 *
448 * 0:eq, 1:gt, 2:ge, 3:lt, 4:le
449 *
450 * The default operator is "eq". It supports range matching. Ranges are
451 * rejected for other operators. The operator may be changed at any time.
452 * The operator is stored in the 'opaque' argument.
453 *
Willy Tarreaua84d3742007-05-07 00:36:48 +0200454 */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200455int acl_parse_int(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200456{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200457 signed long long i;
458 unsigned int j, last, skip = 0;
459 const char *ptr = *text;
460
461
Willy Tarreau8f8e6452007-06-17 21:51:38 +0200462 while (!isdigit((unsigned char)*ptr)) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200463 if (strcmp(ptr, "eq") == 0) *opaque = 0;
464 else if (strcmp(ptr, "gt") == 0) *opaque = 1;
465 else if (strcmp(ptr, "ge") == 0) *opaque = 2;
466 else if (strcmp(ptr, "lt") == 0) *opaque = 3;
467 else if (strcmp(ptr, "le") == 0) *opaque = 4;
468 else
469 return 0;
470
471 skip++;
472 ptr = text[skip];
473 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200474
475 last = i = 0;
476 while (1) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200477 j = *ptr++;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200478 if ((j == '-' || j == ':') && !last) {
479 last++;
480 pattern->val.range.min = i;
481 i = 0;
482 continue;
483 }
484 j -= '0';
485 if (j > 9)
486 // also catches the terminating zero
487 break;
488 i *= 10;
489 i += j;
490 }
Willy Tarreauae8b7962007-06-09 23:10:04 +0200491
492 if (last && *opaque >= 1 && *opaque <= 4)
493 /* having a range with a min or a max is absurd */
494 return 0;
495
Willy Tarreaua84d3742007-05-07 00:36:48 +0200496 if (!last)
497 pattern->val.range.min = i;
498 pattern->val.range.max = i;
Willy Tarreauae8b7962007-06-09 23:10:04 +0200499
500 switch (*opaque) {
501 case 0: /* eq */
502 pattern->val.range.min_set = 1;
503 pattern->val.range.max_set = 1;
504 break;
505 case 1: /* gt */
506 pattern->val.range.min++; /* gt = ge + 1 */
507 case 2: /* ge */
508 pattern->val.range.min_set = 1;
509 pattern->val.range.max_set = 0;
510 break;
511 case 3: /* lt */
512 pattern->val.range.max--; /* lt = le - 1 */
513 case 4: /* le */
514 pattern->val.range.min_set = 0;
515 pattern->val.range.max_set = 1;
516 break;
517 }
518 return skip + 1;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200519}
520
Willy Tarreau4a26d2f2008-07-15 16:05:33 +0200521/* Parse a range of positive 2-component versions delimited by either ':' or
522 * '-'. The version consists in a major and a minor, both of which must be
523 * smaller than 65536, because internally they will be represented as a 32-bit
524 * integer.
525 * If only one version is read, it is set as both min and max. Just like for
526 * pure integers, an operator may be specified as the prefix, among this list
527 * of 5 :
528 *
529 * 0:eq, 1:gt, 2:ge, 3:lt, 4:le
530 *
531 * The default operator is "eq". It supports range matching. Ranges are
532 * rejected for other operators. The operator may be changed at any time.
533 * The operator is stored in the 'opaque' argument. This allows constructs
534 * such as the following one :
535 *
536 * acl obsolete_ssl ssl_req_proto lt 3
537 * acl unsupported_ssl ssl_req_proto gt 3.1
538 * acl valid_ssl ssl_req_proto 3.0-3.1
539 *
540 */
541int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, int *opaque)
542{
543 signed long long i;
544 unsigned int j, last, skip = 0;
545 const char *ptr = *text;
546
547
548 while (!isdigit((unsigned char)*ptr)) {
549 if (strcmp(ptr, "eq") == 0) *opaque = 0;
550 else if (strcmp(ptr, "gt") == 0) *opaque = 1;
551 else if (strcmp(ptr, "ge") == 0) *opaque = 2;
552 else if (strcmp(ptr, "lt") == 0) *opaque = 3;
553 else if (strcmp(ptr, "le") == 0) *opaque = 4;
554 else
555 return 0;
556
557 skip++;
558 ptr = text[skip];
559 }
560
561 last = i = 0;
562 while (1) {
563 j = *ptr++;
564 if (j == '.') {
565 /* minor part */
566 if (i >= 65536)
567 return 0;
568 i <<= 16;
569 continue;
570 }
571 if ((j == '-' || j == ':') && !last) {
572 last++;
573 if (i < 65536)
574 i <<= 16;
575 pattern->val.range.min = i;
576 i = 0;
577 continue;
578 }
579 j -= '0';
580 if (j > 9)
581 // also catches the terminating zero
582 break;
583 i = (i & 0xFFFF0000) + (i & 0xFFFF) * 10;
584 i += j;
585 }
586
587 /* if we only got a major version, let's shift it now */
588 if (i < 65536)
589 i <<= 16;
590
591 if (last && *opaque >= 1 && *opaque <= 4)
592 /* having a range with a min or a max is absurd */
593 return 0;
594
595 if (!last)
596 pattern->val.range.min = i;
597 pattern->val.range.max = i;
598
599 switch (*opaque) {
600 case 0: /* eq */
601 pattern->val.range.min_set = 1;
602 pattern->val.range.max_set = 1;
603 break;
604 case 1: /* gt */
605 pattern->val.range.min++; /* gt = ge + 1 */
606 case 2: /* ge */
607 pattern->val.range.min_set = 1;
608 pattern->val.range.max_set = 0;
609 break;
610 case 3: /* lt */
611 pattern->val.range.max--; /* lt = le - 1 */
612 case 4: /* le */
613 pattern->val.range.min_set = 0;
614 pattern->val.range.max_set = 1;
615 break;
616 }
617 return skip + 1;
618}
619
Willy Tarreaua67fad92007-05-08 19:50:09 +0200620/* Parse an IP address and an optional mask in the form addr[/mask].
621 * The addr may either be an IPv4 address or a hostname. The mask
622 * may either be a dotted mask or a number of bits. Returns 1 if OK,
623 * otherwise 0.
624 */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200625int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua67fad92007-05-08 19:50:09 +0200626{
Willy Tarreaub337b532010-05-13 20:03:41 +0200627 struct eb_root *tree = NULL;
628 if (pattern->flags & ACL_PAT_F_TREE_OK)
629 tree = pattern->val.tree;
630
631 if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask)) {
632 unsigned int mask = ntohl(pattern->val.ipv4.mask.s_addr);
633 struct ebmb_node *node;
634 /* check if the mask is contiguous so that we can insert the
635 * network into the tree. A continuous mask has only ones on
636 * the left. This means that this mask + its lower bit added
637 * once again is null.
638 */
639 if (mask + (mask & -mask) == 0 && tree) {
640 mask = mask ? 33 - flsnz(mask & -mask) : 0; /* equals cidr value */
641 /* FIXME: insert <addr>/<mask> into the tree here */
642 node = calloc(1, sizeof(*node) + 4); /* reserve 4 bytes for IPv4 address */
643 if (!node)
644 return 0;
645 memcpy(node->key, &pattern->val.ipv4.addr, 4); /* network byte order */
646 node->node.pfx = mask;
647 if (ebmb_insert_prefix(tree, node, 4) != node)
648 free(node); /* was a duplicate */
649 pattern->flags |= ACL_PAT_F_TREE;
650 return 1;
651 }
Willy Tarreauae8b7962007-06-09 23:10:04 +0200652 return 1;
Willy Tarreaub337b532010-05-13 20:03:41 +0200653 }
Willy Tarreauae8b7962007-06-09 23:10:04 +0200654 else
655 return 0;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200656}
657
Willy Tarreaua84d3742007-05-07 00:36:48 +0200658/*
659 * Registers the ACL keyword list <kwl> as a list of valid keywords for next
660 * parsing sessions.
661 */
662void acl_register_keywords(struct acl_kw_list *kwl)
663{
664 LIST_ADDQ(&acl_keywords.list, &kwl->list);
665}
666
667/*
668 * Unregisters the ACL keyword list <kwl> from the list of valid keywords.
669 */
670void acl_unregister_keywords(struct acl_kw_list *kwl)
671{
672 LIST_DEL(&kwl->list);
673 LIST_INIT(&kwl->list);
674}
675
676/* Return a pointer to the ACL <name> within the list starting at <head>, or
677 * NULL if not found.
678 */
679struct acl *find_acl_by_name(const char *name, struct list *head)
680{
681 struct acl *acl;
682 list_for_each_entry(acl, head, list) {
683 if (strcmp(acl->name, name) == 0)
684 return acl;
685 }
686 return NULL;
687}
688
689/* Return a pointer to the ACL keyword <kw>, or NULL if not found. Note that if
690 * <kw> contains an opening parenthesis, only the left part of it is checked.
691 */
692struct acl_keyword *find_acl_kw(const char *kw)
693{
694 int index;
695 const char *kwend;
696 struct acl_kw_list *kwl;
697
698 kwend = strchr(kw, '(');
699 if (!kwend)
700 kwend = kw + strlen(kw);
701
702 list_for_each_entry(kwl, &acl_keywords.list, list) {
703 for (index = 0; kwl->kw[index].kw != NULL; index++) {
704 if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
705 kwl->kw[index].kw[kwend-kw] == 0)
706 return &kwl->kw[index];
707 }
708 }
709 return NULL;
710}
711
712static void free_pattern(struct acl_pattern *pat)
713{
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200714
715 if (pat->ptr.ptr) {
716 if (pat->freeptrbuf)
717 pat->freeptrbuf(pat->ptr.ptr);
718
Willy Tarreaua84d3742007-05-07 00:36:48 +0200719 free(pat->ptr.ptr);
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200720 }
721
Willy Tarreaua84d3742007-05-07 00:36:48 +0200722 free(pat);
723}
724
725static void free_pattern_list(struct list *head)
726{
727 struct acl_pattern *pat, *tmp;
728 list_for_each_entry_safe(pat, tmp, head, list)
729 free_pattern(pat);
730}
731
Willy Tarreaue56cda92010-05-11 23:25:05 +0200732static void free_pattern_tree(struct eb_root *root)
733{
734 struct eb_node *node, *next;
735 node = eb_first(root);
736 while (node) {
737 next = eb_next(node);
738 free(node);
739 node = next;
740 }
741}
742
Willy Tarreaua84d3742007-05-07 00:36:48 +0200743static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
744{
745 free_pattern_list(&expr->patterns);
Willy Tarreaue56cda92010-05-11 23:25:05 +0200746 free_pattern_tree(&expr->pattern_tree);
Willy Tarreaua84d3742007-05-07 00:36:48 +0200747 LIST_INIT(&expr->patterns);
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100748 if (expr->arg_len && expr->arg.str)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200749 free(expr->arg.str);
750 expr->kw->use_cnt--;
751 return expr;
752}
753
Willy Tarreau2b5285d2010-05-09 23:45:24 +0200754static int acl_read_patterns_from_file( struct acl_keyword *aclkw,
755 struct acl_expr *expr,
756 const char *filename, int patflags)
757{
758 FILE *file;
759 char *c;
760 const char *args[2];
761 struct acl_pattern *pattern;
762 int opaque;
763
764 file = fopen(filename, "r");
765 if (!file)
766 return 0;
767
768 /* now parse all patterns. The file may contain only one pattern per
769 * line. If the line contains spaces, they will be part of the pattern.
770 * The pattern stops at the first CR, LF or EOF encountered.
771 */
772 opaque = 0;
Willy Tarreaue56cda92010-05-11 23:25:05 +0200773 pattern = NULL;
Willy Tarreau2b5285d2010-05-09 23:45:24 +0200774 args[1] = "";
775 while (fgets(trash, sizeof(trash), file) != NULL) {
776
777 c = trash;
Willy Tarreau58215a02010-05-13 22:07:43 +0200778
779 /* ignore lines beginning with a dash */
780 if (*c == '#')
781 continue;
782
783 /* strip leading spaces and tabs */
784 while (*c == ' ' || *c == '\t')
785 c++;
786
787 /* empty lines are ignored too */
788 if (!*c)
789 continue;
790
791 args[0] = c;
Willy Tarreau2b5285d2010-05-09 23:45:24 +0200792 while (*c && *c != '\n' && *c != '\r')
793 c++;
794 *c = 0;
795
Willy Tarreaue56cda92010-05-11 23:25:05 +0200796 /* we keep the previous pattern along iterations as long as it's not used */
797 if (!pattern)
798 pattern = (struct acl_pattern *)malloc(sizeof(*pattern));
Willy Tarreau2b5285d2010-05-09 23:45:24 +0200799 if (!pattern)
800 goto out_close;
Willy Tarreaue56cda92010-05-11 23:25:05 +0200801
802 memset(pattern, 0, sizeof(*pattern));
Willy Tarreau2b5285d2010-05-09 23:45:24 +0200803 pattern->flags = patflags;
804
Willy Tarreaue56cda92010-05-11 23:25:05 +0200805 if ((aclkw->requires & ACL_MAY_LOOKUP) && !(pattern->flags & ACL_PAT_F_IGNORE_CASE)) {
806 /* we pre-set the data pointer to the tree's head so that functions
807 * which are able to insert in a tree know where to do that.
808 */
809 pattern->flags |= ACL_PAT_F_TREE_OK;
810 pattern->val.tree = &expr->pattern_tree;
811 }
812
Willy Tarreau2b5285d2010-05-09 23:45:24 +0200813 if (!aclkw->parse(args, pattern, &opaque))
814 goto out_free_pattern;
Willy Tarreaue56cda92010-05-11 23:25:05 +0200815
816 /* if the parser did not feed the tree, let's chain the pattern to the list */
817 if (!(pattern->flags & ACL_PAT_F_TREE)) {
818 LIST_ADDQ(&expr->patterns, &pattern->list);
819 pattern = NULL; /* get a new one */
820 }
Willy Tarreau2b5285d2010-05-09 23:45:24 +0200821 }
Willy Tarreaue56cda92010-05-11 23:25:05 +0200822 if (pattern)
823 free_pattern(pattern);
Willy Tarreau2b5285d2010-05-09 23:45:24 +0200824 return 1;
825
826 out_free_pattern:
827 free_pattern(pattern);
828 out_close:
829 fclose(file);
830 return 0;
831}
832
Willy Tarreaua84d3742007-05-07 00:36:48 +0200833/* Parse an ACL expression starting at <args>[0], and return it.
834 * Right now, the only accepted syntax is :
835 * <subject> [<value>...]
836 */
837struct acl_expr *parse_acl_expr(const char **args)
838{
839 __label__ out_return, out_free_expr, out_free_pattern;
840 struct acl_expr *expr;
841 struct acl_keyword *aclkw;
842 struct acl_pattern *pattern;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200843 int opaque, patflags;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200844 const char *arg;
845
846 aclkw = find_acl_kw(args[0]);
847 if (!aclkw || !aclkw->parse)
848 goto out_return;
849
850 expr = (struct acl_expr *)calloc(1, sizeof(*expr));
851 if (!expr)
852 goto out_return;
853
854 expr->kw = aclkw;
855 aclkw->use_cnt++;
856 LIST_INIT(&expr->patterns);
Willy Tarreaue56cda92010-05-11 23:25:05 +0200857 expr->pattern_tree = EB_ROOT_UNIQUE;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200858 expr->arg.str = NULL;
Willy Tarreaubb768912007-06-10 11:17:01 +0200859 expr->arg_len = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200860
861 arg = strchr(args[0], '(');
862 if (arg != NULL) {
863 char *end, *arg2;
864 /* there is an argument in the form "subject(arg)" */
865 arg++;
866 end = strchr(arg, ')');
867 if (!end)
868 goto out_free_expr;
Willy Tarreauac778f52010-01-26 19:02:46 +0100869 arg2 = my_strndup(arg, end - arg);
Willy Tarreau1edb1442010-01-27 20:13:38 +0100870 if (!arg2)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200871 goto out_free_expr;
Willy Tarreaubb768912007-06-10 11:17:01 +0200872 expr->arg_len = end - arg;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200873 expr->arg.str = arg2;
874 }
875
Willy Tarreaua84d3742007-05-07 00:36:48 +0200876 args++;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200877
878 /* check for options before patterns. Supported options are :
879 * -i : ignore case for all patterns by default
880 * -f : read patterns from those files
881 * -- : everything after this is not an option
882 */
883 patflags = 0;
884 while (**args == '-') {
885 if ((*args)[1] == 'i')
886 patflags |= ACL_PAT_F_IGNORE_CASE;
Willy Tarreau2b5285d2010-05-09 23:45:24 +0200887 else if ((*args)[1] == 'f') {
888 if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE))
889 goto out_free_expr;
890 args++;
891 }
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200892 else if ((*args)[1] == '-') {
893 args++;
894 break;
895 }
896 else
897 break;
898 args++;
899 }
900
901 /* now parse all patterns */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200902 opaque = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200903 while (**args) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200904 int ret;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200905 pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
906 if (!pattern)
907 goto out_free_expr;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200908 pattern->flags = patflags;
909
Willy Tarreauae8b7962007-06-09 23:10:04 +0200910 ret = aclkw->parse(args, pattern, &opaque);
911 if (!ret)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200912 goto out_free_pattern;
913 LIST_ADDQ(&expr->patterns, &pattern->list);
Willy Tarreauae8b7962007-06-09 23:10:04 +0200914 args += ret;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200915 }
916
917 return expr;
918
919 out_free_pattern:
920 free_pattern(pattern);
921 out_free_expr:
922 prune_acl_expr(expr);
923 free(expr);
924 out_return:
925 return NULL;
926}
927
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +0200928/* Purge everything in the acl <acl>, then return <acl>. */
929struct acl *prune_acl(struct acl *acl) {
930
931 struct acl_expr *expr, *exprb;
932
933 free(acl->name);
934
935 list_for_each_entry_safe(expr, exprb, &acl->expr, list) {
936 LIST_DEL(&expr->list);
937 prune_acl_expr(expr);
938 free(expr);
939 }
940
941 return acl;
942}
943
Willy Tarreaua84d3742007-05-07 00:36:48 +0200944/* Parse an ACL with the name starting at <args>[0], and with a list of already
945 * known ACLs in <acl>. If the ACL was not in the list, it will be added.
Willy Tarreau2a56c5e2010-03-15 16:13:29 +0100946 * A pointer to that ACL is returned. If the ACL has an empty name, then it's
947 * an anonymous one and it won't be merged with any other one.
Willy Tarreaua84d3742007-05-07 00:36:48 +0200948 *
949 * args syntax: <aclname> <acl_expr>
950 */
951struct acl *parse_acl(const char **args, struct list *known_acl)
952{
953 __label__ out_return, out_free_acl_expr, out_free_name;
954 struct acl *cur_acl;
955 struct acl_expr *acl_expr;
956 char *name;
957
Willy Tarreau2a56c5e2010-03-15 16:13:29 +0100958 if (**args && invalid_char(*args))
Willy Tarreau2e74c3f2007-12-02 18:45:09 +0100959 goto out_return;
960
Willy Tarreaua84d3742007-05-07 00:36:48 +0200961 acl_expr = parse_acl_expr(args + 1);
962 if (!acl_expr)
963 goto out_return;
964
Willy Tarreau404e8ab2009-07-26 19:40:40 +0200965 /* Check for args beginning with an opening parenthesis just after the
966 * subject, as this is almost certainly a typo. Right now we can only
967 * emit a warning, so let's do so.
968 */
Krzysztof Piotr Oledzki4cdd8312009-10-05 00:23:35 +0200969 if (!strchr(args[1], '(') && *args[2] == '(')
Willy Tarreau404e8ab2009-07-26 19:40:40 +0200970 Warning("parsing acl '%s' :\n"
971 " matching '%s' for pattern '%s' is likely a mistake and probably\n"
972 " not what you want. Maybe you need to remove the extraneous space before '('.\n"
973 " If you are really sure this is not an error, please insert '--' between the\n"
974 " match and the pattern to make this warning message disappear.\n",
975 args[0], args[1], args[2]);
976
Willy Tarreau2a56c5e2010-03-15 16:13:29 +0100977 if (*args[0])
978 cur_acl = find_acl_by_name(args[0], known_acl);
979 else
980 cur_acl = NULL;
981
Willy Tarreaua84d3742007-05-07 00:36:48 +0200982 if (!cur_acl) {
983 name = strdup(args[0]);
984 if (!name)
985 goto out_free_acl_expr;
986 cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
987 if (cur_acl == NULL)
988 goto out_free_name;
989
990 LIST_INIT(&cur_acl->expr);
991 LIST_ADDQ(known_acl, &cur_acl->list);
992 cur_acl->name = name;
993 }
994
Willy Tarreaua9802632008-07-25 19:13:19 +0200995 cur_acl->requires |= acl_expr->kw->requires;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200996 LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
997 return cur_acl;
998
999 out_free_name:
1000 free(name);
1001 out_free_acl_expr:
1002 prune_acl_expr(acl_expr);
1003 free(acl_expr);
1004 out_return:
1005 return NULL;
1006}
1007
Willy Tarreau16fbe822007-06-17 11:54:31 +02001008/* Some useful ACLs provided by default. Only those used are allocated. */
1009
1010const struct {
1011 const char *name;
1012 const char *expr[4]; /* put enough for longest expression */
1013} default_acl_list[] = {
Willy Tarreau58393e12008-07-20 10:39:22 +02001014 { .name = "TRUE", .expr = {"always_true",""}},
1015 { .name = "FALSE", .expr = {"always_false",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +02001016 { .name = "LOCALHOST", .expr = {"src","127.0.0.1/8",""}},
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001017 { .name = "HTTP", .expr = {"req_proto_http",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +02001018 { .name = "HTTP_1.0", .expr = {"req_ver","1.0",""}},
1019 { .name = "HTTP_1.1", .expr = {"req_ver","1.1",""}},
1020 { .name = "METH_CONNECT", .expr = {"method","CONNECT",""}},
1021 { .name = "METH_GET", .expr = {"method","GET","HEAD",""}},
1022 { .name = "METH_HEAD", .expr = {"method","HEAD",""}},
1023 { .name = "METH_OPTIONS", .expr = {"method","OPTIONS",""}},
1024 { .name = "METH_POST", .expr = {"method","POST",""}},
1025 { .name = "METH_TRACE", .expr = {"method","TRACE",""}},
1026 { .name = "HTTP_URL_ABS", .expr = {"url_reg","^[^/:]*://",""}},
1027 { .name = "HTTP_URL_SLASH", .expr = {"url_beg","/",""}},
1028 { .name = "HTTP_URL_STAR", .expr = {"url","*",""}},
1029 { .name = "HTTP_CONTENT", .expr = {"hdr_val(content-length)","gt","0",""}},
Emeric Brunbede3d02009-06-30 17:54:00 +02001030 { .name = "RDP_COOKIE", .expr = {"req_rdp_cookie_cnt","gt","0",""}},
Willy Tarreauc6317702008-07-20 09:29:50 +02001031 { .name = "REQ_CONTENT", .expr = {"req_len","gt","0",""}},
Willy Tarreaub6fb4202008-07-20 11:18:28 +02001032 { .name = "WAIT_END", .expr = {"wait_end",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +02001033 { .name = NULL, .expr = {""}}
1034};
1035
1036/* Find a default ACL from the default_acl list, compile it and return it.
1037 * If the ACL is not found, NULL is returned. In theory, it cannot fail,
1038 * except when default ACLs are broken, in which case it will return NULL.
1039 * If <known_acl> is not NULL, the ACL will be queued at its tail.
1040 */
1041struct acl *find_acl_default(const char *acl_name, struct list *known_acl)
1042{
1043 __label__ out_return, out_free_acl_expr, out_free_name;
1044 struct acl *cur_acl;
1045 struct acl_expr *acl_expr;
1046 char *name;
1047 int index;
1048
1049 for (index = 0; default_acl_list[index].name != NULL; index++) {
1050 if (strcmp(acl_name, default_acl_list[index].name) == 0)
1051 break;
1052 }
1053
1054 if (default_acl_list[index].name == NULL)
1055 return NULL;
1056
1057 acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr);
1058 if (!acl_expr)
1059 goto out_return;
1060
1061 name = strdup(acl_name);
1062 if (!name)
1063 goto out_free_acl_expr;
1064 cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
1065 if (cur_acl == NULL)
1066 goto out_free_name;
1067
1068 cur_acl->name = name;
Willy Tarreaua55b7dc2009-07-12 09:21:30 +02001069 cur_acl->requires |= acl_expr->kw->requires;
Willy Tarreau16fbe822007-06-17 11:54:31 +02001070 LIST_INIT(&cur_acl->expr);
1071 LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
1072 if (known_acl)
1073 LIST_ADDQ(known_acl, &cur_acl->list);
1074
1075 return cur_acl;
1076
1077 out_free_name:
1078 free(name);
1079 out_free_acl_expr:
1080 prune_acl_expr(acl_expr);
1081 free(acl_expr);
1082 out_return:
1083 return NULL;
1084}
Willy Tarreaua84d3742007-05-07 00:36:48 +02001085
1086/* Purge everything in the acl_cond <cond>, then return <cond>. */
1087struct acl_cond *prune_acl_cond(struct acl_cond *cond)
1088{
1089 struct acl_term_suite *suite, *tmp_suite;
1090 struct acl_term *term, *tmp_term;
1091
1092 /* iterate through all term suites and free all terms and all suites */
1093 list_for_each_entry_safe(suite, tmp_suite, &cond->suites, list) {
1094 list_for_each_entry_safe(term, tmp_term, &suite->terms, list)
1095 free(term);
1096 free(suite);
1097 }
1098 return cond;
1099}
1100
1101/* Parse an ACL condition starting at <args>[0], relying on a list of already
1102 * known ACLs passed in <known_acl>. The new condition is returned (or NULL in
1103 * case of low memory). Supports multiple conditions separated by "or".
1104 */
1105struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol)
1106{
1107 __label__ out_return, out_free_suite, out_free_term;
Willy Tarreau74b98a82007-06-16 19:35:18 +02001108 int arg, neg;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001109 const char *word;
1110 struct acl *cur_acl;
1111 struct acl_term *cur_term;
1112 struct acl_term_suite *cur_suite;
1113 struct acl_cond *cond;
1114
1115 cond = (struct acl_cond *)calloc(1, sizeof(*cond));
1116 if (cond == NULL)
1117 goto out_return;
1118
1119 LIST_INIT(&cond->list);
1120 LIST_INIT(&cond->suites);
1121 cond->pol = pol;
1122
1123 cur_suite = NULL;
Willy Tarreau74b98a82007-06-16 19:35:18 +02001124 neg = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001125 for (arg = 0; *args[arg]; arg++) {
1126 word = args[arg];
1127
1128 /* remove as many exclamation marks as we can */
1129 while (*word == '!') {
1130 neg = !neg;
1131 word++;
1132 }
1133
1134 /* an empty word is allowed because we cannot force the user to
1135 * always think about not leaving exclamation marks alone.
1136 */
1137 if (!*word)
1138 continue;
1139
Willy Tarreau16fbe822007-06-17 11:54:31 +02001140 if (strcasecmp(word, "or") == 0 || strcmp(word, "||") == 0) {
Willy Tarreaua84d3742007-05-07 00:36:48 +02001141 /* new term suite */
1142 cur_suite = NULL;
1143 neg = 0;
1144 continue;
1145 }
1146
Willy Tarreau95fa4692010-02-01 13:05:50 +01001147 if (strcmp(word, "{") == 0) {
1148 /* we may have a complete ACL expression between two braces,
1149 * find the last one.
1150 */
1151 int arg_end = arg + 1;
1152 const char **args_new;
1153
1154 while (*args[arg_end] && strcmp(args[arg_end], "}") != 0)
1155 arg_end++;
1156
1157 if (!*args[arg_end])
1158 goto out_free_suite;
1159
1160 args_new = calloc(1, (arg_end - arg + 1) * sizeof(*args_new));
1161 if (!args_new)
1162 goto out_free_suite;
1163
Willy Tarreau2a56c5e2010-03-15 16:13:29 +01001164 args_new[0] = "";
Willy Tarreau95fa4692010-02-01 13:05:50 +01001165 memcpy(args_new + 1, args + arg + 1, (arg_end - arg) * sizeof(*args_new));
1166 args_new[arg_end - arg] = "";
1167 cur_acl = parse_acl(args_new, known_acl);
1168 free(args_new);
1169
1170 if (!cur_acl)
Willy Tarreau16fbe822007-06-17 11:54:31 +02001171 goto out_free_suite;
Willy Tarreau95fa4692010-02-01 13:05:50 +01001172 arg = arg_end;
1173 }
1174 else {
1175 /* search for <word> in the known ACL names. If we do not find
1176 * it, let's look for it in the default ACLs, and if found, add
1177 * it to the list of ACLs of this proxy. This makes it possible
1178 * to override them.
1179 */
1180 cur_acl = find_acl_by_name(word, known_acl);
1181 if (cur_acl == NULL) {
1182 cur_acl = find_acl_default(word, known_acl);
1183 if (cur_acl == NULL)
1184 goto out_free_suite;
1185 }
Willy Tarreau16fbe822007-06-17 11:54:31 +02001186 }
Willy Tarreaua84d3742007-05-07 00:36:48 +02001187
1188 cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term));
1189 if (cur_term == NULL)
1190 goto out_free_suite;
1191
1192 cur_term->acl = cur_acl;
1193 cur_term->neg = neg;
Willy Tarreaua9802632008-07-25 19:13:19 +02001194 cond->requires |= cur_acl->requires;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001195
1196 if (!cur_suite) {
1197 cur_suite = (struct acl_term_suite *)calloc(1, sizeof(*cur_suite));
1198 if (cur_term == NULL)
1199 goto out_free_term;
1200 LIST_INIT(&cur_suite->terms);
1201 LIST_ADDQ(&cond->suites, &cur_suite->list);
1202 }
1203 LIST_ADDQ(&cur_suite->terms, &cur_term->list);
Willy Tarreau74b98a82007-06-16 19:35:18 +02001204 neg = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001205 }
1206
1207 return cond;
1208
1209 out_free_term:
1210 free(cur_term);
1211 out_free_suite:
1212 prune_acl_cond(cond);
1213 free(cond);
1214 out_return:
1215 return NULL;
1216}
1217
Willy Tarreau2bbba412010-01-28 16:48:33 +01001218/* Builds an ACL condition starting at the if/unless keyword. The complete
1219 * condition is returned. NULL is returned in case of error or if the first
1220 * word is neither "if" nor "unless". It automatically sets the file name and
1221 * the line number in the condition for better error reporting, and adds the
1222 * ACL requirements to the proxy's acl_requires.
1223 */
1224struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args)
1225{
1226 int pol = ACL_COND_NONE;
1227 struct acl_cond *cond = NULL;
1228
1229 if (!strcmp(*args, "if")) {
1230 pol = ACL_COND_IF;
1231 args++;
1232 }
1233 else if (!strcmp(*args, "unless")) {
1234 pol = ACL_COND_UNLESS;
1235 args++;
1236 }
1237 else
1238 return NULL;
1239
1240 cond = parse_acl_cond(args, &px->acl, pol);
1241 if (!cond)
1242 return NULL;
1243
1244 cond->file = file;
1245 cond->line = line;
1246 px->acl_requires |= cond->requires;
1247
1248 return cond;
1249}
1250
Willy Tarreau11382812008-07-09 16:18:21 +02001251/* Execute condition <cond> and return either ACL_PAT_FAIL, ACL_PAT_MISS or
Willy Tarreaub6866442008-07-14 23:54:42 +02001252 * ACL_PAT_PASS depending on the test results. ACL_PAT_MISS may only be
1253 * returned if <dir> contains ACL_PARTIAL, indicating that incomplete data
1254 * is being examined.
1255 * This function only computes the condition, it does not apply the polarity
1256 * required by IF/UNLESS, it's up to the caller to do this using something like
1257 * this :
Willy Tarreau11382812008-07-09 16:18:21 +02001258 *
1259 * res = acl_pass(res);
Willy Tarreaub6866442008-07-14 23:54:42 +02001260 * if (res == ACL_PAT_MISS)
1261 * return 0;
Willy Tarreau11382812008-07-09 16:18:21 +02001262 * if (cond->pol == ACL_COND_UNLESS)
1263 * res = !res;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001264 */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001265int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, void *l7, int dir)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001266{
1267 __label__ fetch_next;
1268 struct acl_term_suite *suite;
1269 struct acl_term *term;
1270 struct acl_expr *expr;
1271 struct acl *acl;
1272 struct acl_pattern *pattern;
1273 struct acl_test test;
Willy Tarreau11382812008-07-09 16:18:21 +02001274 int acl_res, suite_res, cond_res;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001275
Willy Tarreau11382812008-07-09 16:18:21 +02001276 /* We're doing a logical OR between conditions so we initialize to FAIL.
1277 * The MISS status is propagated down from the suites.
1278 */
Willy Tarreaua84d3742007-05-07 00:36:48 +02001279 cond_res = ACL_PAT_FAIL;
1280 list_for_each_entry(suite, &cond->suites, list) {
Willy Tarreau11382812008-07-09 16:18:21 +02001281 /* Evaluate condition suite <suite>. We stop at the first term
1282 * which returns ACL_PAT_FAIL. The MISS status is still propagated
1283 * in case of uncertainty in the result.
Willy Tarreaua84d3742007-05-07 00:36:48 +02001284 */
1285
1286 /* we're doing a logical AND between terms, so we must set the
1287 * initial value to PASS.
1288 */
1289 suite_res = ACL_PAT_PASS;
1290 list_for_each_entry(term, &suite->terms, list) {
1291 acl = term->acl;
1292
1293 /* FIXME: use cache !
1294 * check acl->cache_idx for this.
1295 */
1296
1297 /* ACL result not cached. Let's scan all the expressions
1298 * and use the first one to match.
1299 */
1300 acl_res = ACL_PAT_FAIL;
1301 list_for_each_entry(expr, &acl->expr, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001302 /* we need to reset context and flags */
1303 memset(&test, 0, sizeof(test));
Willy Tarreaua84d3742007-05-07 00:36:48 +02001304 fetch_next:
Willy Tarreaub6866442008-07-14 23:54:42 +02001305 if (!expr->kw->fetch(px, l4, l7, dir, expr, &test)) {
1306 /* maybe we could not fetch because of missing data */
1307 if (test.flags & ACL_TEST_F_MAY_CHANGE && dir & ACL_PARTIAL)
1308 acl_res |= ACL_PAT_MISS;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001309 continue;
Willy Tarreaub6866442008-07-14 23:54:42 +02001310 }
Willy Tarreaua84d3742007-05-07 00:36:48 +02001311
Willy Tarreaua79534f2008-07-20 10:13:37 +02001312 if (test.flags & ACL_TEST_F_RES_SET) {
1313 if (test.flags & ACL_TEST_F_RES_PASS)
1314 acl_res |= ACL_PAT_PASS;
1315 else
1316 acl_res |= ACL_PAT_FAIL;
1317 }
1318 else {
Willy Tarreau020534d2010-05-16 21:45:45 +02001319 if (!eb_is_empty(&expr->pattern_tree)) {
Willy Tarreauc4262962010-05-10 23:42:40 +02001320 /* a tree is present, let's check what type it is */
1321 if (expr->kw->match == acl_match_str)
1322 acl_res |= acl_lookup_str(&test, expr) ? ACL_PAT_PASS : ACL_PAT_FAIL;
Willy Tarreaub337b532010-05-13 20:03:41 +02001323 else if (expr->kw->match == acl_match_ip)
1324 acl_res |= acl_lookup_ip(&test, expr) ? ACL_PAT_PASS : ACL_PAT_FAIL;
Willy Tarreauc4262962010-05-10 23:42:40 +02001325 }
1326
Willy Tarreaua79534f2008-07-20 10:13:37 +02001327 /* call the match() function for all tests on this value */
1328 list_for_each_entry(pattern, &expr->patterns, list) {
Willy Tarreaua79534f2008-07-20 10:13:37 +02001329 if (acl_res == ACL_PAT_PASS)
1330 break;
Willy Tarreaue56cda92010-05-11 23:25:05 +02001331 acl_res |= expr->kw->match(&test, pattern);
Willy Tarreaua79534f2008-07-20 10:13:37 +02001332 }
Krzysztof Piotr Oledzkid7528e52010-01-29 17:55:53 +01001333
Willy Tarreaue56cda92010-05-11 23:25:05 +02001334 if ((test.flags & ACL_TEST_F_NULL_MATCH) &&
Willy Tarreau020534d2010-05-16 21:45:45 +02001335 LIST_ISEMPTY(&expr->patterns) && eb_is_empty(&expr->pattern_tree))
Krzysztof Piotr Oledzkid7528e52010-01-29 17:55:53 +01001336 acl_res |= expr->kw->match(&test, NULL);
Willy Tarreaua84d3742007-05-07 00:36:48 +02001337 }
1338 /*
Willy Tarreau11382812008-07-09 16:18:21 +02001339 * OK now acl_res holds the result of this expression
1340 * as one of ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
Willy Tarreaua84d3742007-05-07 00:36:48 +02001341 *
Willy Tarreau11382812008-07-09 16:18:21 +02001342 * Then if (!MISS) we can cache the result, and put
Willy Tarreaua84d3742007-05-07 00:36:48 +02001343 * (test.flags & ACL_TEST_F_VOLATILE) in the cache flags.
1344 *
1345 * FIXME: implement cache.
1346 *
1347 */
1348
1349 /* now we may have some cleanup to do */
1350 if (test.flags & ACL_TEST_F_MUST_FREE) {
1351 free(test.ptr);
1352 test.len = 0;
1353 }
1354
Willy Tarreau11382812008-07-09 16:18:21 +02001355 /* we're ORing these terms, so a single PASS is enough */
1356 if (acl_res == ACL_PAT_PASS)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001357 break;
1358
Willy Tarreaua84d3742007-05-07 00:36:48 +02001359 if (test.flags & ACL_TEST_F_FETCH_MORE)
1360 goto fetch_next;
Willy Tarreaub6866442008-07-14 23:54:42 +02001361
1362 /* sometimes we know the fetched data is subject to change
1363 * later and give another chance for a new match (eg: request
1364 * size, time, ...)
1365 */
1366 if (test.flags & ACL_TEST_F_MAY_CHANGE && dir & ACL_PARTIAL)
1367 acl_res |= ACL_PAT_MISS;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001368 }
1369 /*
1370 * Here we have the result of an ACL (cached or not).
1371 * ACLs are combined, negated or not, to form conditions.
1372 */
1373
Willy Tarreaua84d3742007-05-07 00:36:48 +02001374 if (term->neg)
Willy Tarreau11382812008-07-09 16:18:21 +02001375 acl_res = acl_neg(acl_res);
Willy Tarreaua84d3742007-05-07 00:36:48 +02001376
1377 suite_res &= acl_res;
Willy Tarreau11382812008-07-09 16:18:21 +02001378
1379 /* we're ANDing these terms, so a single FAIL is enough */
1380 if (suite_res == ACL_PAT_FAIL)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001381 break;
1382 }
1383 cond_res |= suite_res;
Willy Tarreau11382812008-07-09 16:18:21 +02001384
1385 /* we're ORing these terms, so a single PASS is enough */
1386 if (cond_res == ACL_PAT_PASS)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001387 break;
1388 }
Willy Tarreau11382812008-07-09 16:18:21 +02001389 return cond_res;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001390}
1391
1392
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001393/* Reports a pointer to the first ACL used in condition <cond> which requires
1394 * at least one of the USE_FLAGS in <require>. Returns NULL if none matches.
1395 * The construct is almost the same as for acl_exec_cond() since we're walking
1396 * down the ACL tree as well. It is important that the tree is really walked
1397 * through and never cached, because that way, this function can be used as a
1398 * late check.
1399 */
Willy Tarreauf1e98b82010-01-28 17:59:39 +01001400struct acl *cond_find_require(const struct acl_cond *cond, unsigned int require)
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001401{
1402 struct acl_term_suite *suite;
1403 struct acl_term *term;
1404 struct acl *acl;
1405
1406 list_for_each_entry(suite, &cond->suites, list) {
1407 list_for_each_entry(term, &suite->terms, list) {
1408 acl = term->acl;
1409 if (acl->requires & require)
1410 return acl;
1411 }
1412 }
1413 return NULL;
1414}
1415
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001416/*
1417 * Find targets for userlist and groups in acl. Function returns the number
1418 * of errors or OK if everything is fine.
1419 */
1420int
1421acl_find_targets(struct proxy *p)
1422{
1423
1424 struct acl *acl;
1425 struct acl_expr *expr;
1426 struct acl_pattern *pattern;
1427 struct userlist *ul;
1428 int cfgerr = 0;
1429
1430 list_for_each_entry(acl, &p->acl, list) {
1431 list_for_each_entry(expr, &acl->expr, list) {
Willy Tarreau0b1cd942010-05-16 22:18:27 +02001432 if (strcmp(expr->kw->kw, "srv_is_up") == 0) {
1433 struct proxy *px;
1434 struct server *srv;
1435 char *pname, *sname;
1436
1437 if (!expr->arg.str || !*expr->arg.str) {
1438 Alert("proxy %s: acl %s %s(): missing server name.\n",
1439 p->id, acl->name, expr->kw->kw);
1440 cfgerr++;
1441 continue;
1442 }
1443
1444 pname = expr->arg.str;
1445 sname = strrchr(pname, '/');
1446
1447 if (sname)
1448 *sname++ = '\0';
1449 else {
1450 sname = pname;
1451 pname = NULL;
1452 }
1453
1454 px = p;
1455 if (pname) {
1456 px = findproxy(pname, PR_CAP_BE);
1457 if (!px) {
1458 Alert("proxy %s: acl %s %s(): unable to find proxy '%s'.\n",
1459 p->id, acl->name, expr->kw->kw, pname);
1460 cfgerr++;
1461 continue;
1462 }
1463 }
1464
1465 srv = findserver(px, sname);
1466 if (!srv) {
1467 Alert("proxy %s: acl %s %s(): unable to find server '%s'.\n",
1468 p->id, acl->name, expr->kw->kw, sname);
1469 cfgerr++;
1470 continue;
1471 }
1472
1473 free(expr->arg.str);
1474 expr->arg_len = 0;
1475 expr->arg.srv = srv;
1476 continue;
1477 }
1478
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001479 if (strstr(expr->kw->kw, "http_auth") == expr->kw->kw) {
1480
1481 if (!expr->arg.str || !*expr->arg.str) {
1482 Alert("proxy %s: acl %s %s(): missing userlist name.\n",
1483 p->id, acl->name, expr->kw->kw);
1484 cfgerr++;
1485 continue;
1486 }
1487
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01001488 if (p->uri_auth && p->uri_auth->userlist &&
1489 !strcmp(p->uri_auth->userlist->name, expr->arg.str))
1490 ul = p->uri_auth->userlist;
1491 else
1492 ul = auth_find_userlist(expr->arg.str);
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001493
1494 if (!ul) {
1495 Alert("proxy %s: acl %s %s(%s): unable to find userlist.\n",
1496 p->id, acl->name, expr->kw->kw, expr->arg.str);
1497 cfgerr++;
1498 continue;
1499 }
1500
1501 expr->arg_len = 0;
1502 expr->arg.ul = ul;
1503 }
1504
1505
1506 if (!strcmp(expr->kw->kw, "http_auth_group")) {
1507
1508 if (LIST_ISEMPTY(&expr->patterns)) {
1509 Alert("proxy %s: acl %s %s(): no groups specified.\n",
1510 p->id, acl->name, expr->kw->kw);
1511 cfgerr++;
1512 continue;
1513 }
1514
1515 list_for_each_entry(pattern, &expr->patterns, list) {
1516 pattern->val.group_mask = auth_resolve_groups(expr->arg.ul, pattern->ptr.str);
1517
1518 free(pattern->ptr.str);
1519 pattern->ptr.str = NULL;
1520 pattern->len = 0;
1521
1522 if (!pattern->val.group_mask) {
1523 Alert("proxy %s: acl %s %s(): invalid group(s).\n",
1524 p->id, acl->name, expr->kw->kw);
1525 cfgerr++;
1526 continue;
1527 }
1528 }
1529 }
1530 }
1531 }
1532
1533 return cfgerr;
1534}
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001535
Willy Tarreaua84d3742007-05-07 00:36:48 +02001536/************************************************************************/
1537/* All supported keywords must be declared here. */
1538/************************************************************************/
1539
1540/* Note: must not be declared <const> as its list will be overwritten */
1541static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02001542 { "always_true", acl_parse_nothing, acl_fetch_true, acl_match_nothing, ACL_USE_NOTHING },
1543 { "always_false", acl_parse_nothing, acl_fetch_false, acl_match_nothing, ACL_USE_NOTHING },
1544 { "wait_end", acl_parse_nothing, acl_fetch_wait_end, acl_match_nothing, ACL_USE_NOTHING },
Willy Tarreaua84d3742007-05-07 00:36:48 +02001545#if 0
1546 { "time", acl_parse_time, acl_fetch_time, acl_match_time },
1547#endif
1548 { NULL, NULL, NULL, NULL }
1549}};
1550
1551
1552__attribute__((constructor))
1553static void __acl_init(void)
1554{
1555 acl_register_keywords(&acl_kws);
1556}
1557
1558
1559/*
1560 * Local variables:
1561 * c-indent-level: 8
1562 * c-basic-offset: 8
1563 * End:
1564 */