22
22
#include <types/global.h>
24
24
#include <proto/acl.h>
25
#include <proto/arg.h>
25
26
#include <proto/auth.h>
27
#include <proto/channel.h>
26
28
#include <proto/log.h>
29
#include <proto/pattern.h>
27
30
#include <proto/proxy.h>
31
#include <proto/sample.h>
32
#include <proto/stick_table.h>
29
34
#include <ebsttree.h>
31
/* The capabilities of filtering hooks describe the type of information
32
* available to each of them.
34
const 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,
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,
53
36
/* List head of all known ACL keywords */
54
37
static struct acl_kw_list acl_keywords = {
55
38
.list = LIST_HEAD_INIT(acl_keywords.list)
60
* These functions are only used for debugging complex configurations.
63
/* force TRUE to be returned at the fetch level */
65
acl_fetch_true(struct proxy *px, struct session *l4, void *l7, int dir,
66
struct acl_expr *expr, struct acl_test *test)
68
test->flags |= ACL_TEST_F_SET_RES_PASS;
72
/* wait for more data as long as possible, then return TRUE. This should be
73
* used with content inspection.
76
acl_fetch_wait_end(struct proxy *px, struct session *l4, void *l7, int dir,
77
struct acl_expr *expr, struct acl_test *test)
79
if (dir & ACL_PARTIAL) {
80
test->flags |= ACL_TEST_F_MAY_CHANGE;
83
test->flags |= ACL_TEST_F_SET_RES_PASS;
87
/* force FALSE to be returned at the fetch level */
89
acl_fetch_false(struct proxy *px, struct session *l4, void *l7, int dir,
90
struct acl_expr *expr, struct acl_test *test)
92
test->flags |= ACL_TEST_F_SET_RES_FAIL;
98
* These functions are exported and may be used by any other component.
101
/* ignore the current line */
102
int acl_parse_nothing(const char **text, struct acl_pattern *pattern, int *opaque)
107
/* always fake a data retrieval */
108
int acl_fetch_nothing(struct proxy *px, struct session *l4, void *l7, int dir,
109
struct acl_expr *expr, struct acl_test *test)
114
/* always return false */
115
int acl_match_nothing(struct acl_test *test, struct acl_pattern *pattern)
121
/* NB: For two strings to be identical, it is required that their lengths match */
122
int acl_match_str(struct acl_test *test, struct acl_pattern *pattern)
126
if (pattern->len != test->len)
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))
136
/* Lookup a string in the expression's pattern tree. The node is returned if it
137
* exists, otherwise NULL.
139
void *acl_lookup_str(struct acl_test *test, struct acl_expr *expr)
141
/* data are stored in a tree */
142
struct ebmb_node *node;
145
/* we may have to force a trailing zero on the test pattern */
146
prev = test->ptr[test->len];
148
test->ptr[test->len] = '\0';
149
node = ebst_lookup(&expr->pattern_tree, test->ptr);
151
test->ptr[test->len] = prev;
155
/* 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.
160
int acl_match_reg(struct acl_test *test, struct acl_pattern *pattern)
165
if (unlikely(test->flags & ACL_TEST_F_READ_ONLY)) {
168
new_str = calloc(1, test->len + 1);
172
memcpy(new_str, test->ptr, test->len);
173
new_str[test->len] = 0;
174
if (test->flags & ACL_TEST_F_MUST_FREE)
177
test->flags |= ACL_TEST_F_MUST_FREE;
178
test->flags &= ~ACL_TEST_F_READ_ONLY;
181
old_char = test->ptr[test->len];
182
test->ptr[test->len] = 0;
184
if (regexec(pattern->ptr.reg, test->ptr, 0, NULL, 0) == 0)
189
test->ptr[test->len] = old_char;
193
/* Checks that the pattern matches the beginning of the tested string. */
194
int acl_match_beg(struct acl_test *test, struct acl_pattern *pattern)
198
if (pattern->len > test->len)
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))
208
/* Checks that the pattern matches the end of the tested string. */
209
int acl_match_end(struct acl_test *test, struct acl_pattern *pattern)
213
if (pattern->len > test->len)
215
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))
222
/* Checks that the pattern is included inside the tested string.
223
* NB: Suboptimal, should be rewritten using a Boyer-Moore method.
225
int acl_match_sub(struct acl_test *test, struct acl_pattern *pattern)
231
if (pattern->len > test->len)
234
end = test->ptr + test->len - pattern->len;
235
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
237
for (c = test->ptr; c <= end; c++) {
238
if (tolower(*c) != tolower(*pattern->ptr.str))
240
if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
244
for (c = test->ptr; c <= end; c++) {
245
if (*c != *pattern->ptr.str)
247
if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
254
/* Background: Fast way to find a zero byte in a word
255
* http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
256
* hasZeroByte = (v - 0x01010101UL) & ~v & 0x80808080UL;
258
* To look for 4 different byte values, xor the word with those bytes and
259
* then check for zero bytes:
261
* v = (((unsigned char)c * 0x1010101U) ^ delimiter)
262
* where <delimiter> is the 4 byte values to look for (as an uint)
263
* and <c> is the character that is being tested
265
static inline unsigned int is_delimiter(unsigned char c, unsigned int mask)
267
mask ^= (c * 0x01010101); /* propagate the char to all 4 bytes */
268
return (mask - 0x01010101) & ~mask & 0x80808080U;
271
static inline unsigned int make_4delim(unsigned char d1, unsigned char d2, unsigned char d3, unsigned char d4)
273
return d1 << 24 | d2 << 16 | d3 << 8 | d4;
276
/* This one is used by other real functions. It checks that the pattern is
277
* included inside the tested string, but enclosed between the specified
278
* delimiters or at the beginning or end of the string. The delimiters are
279
* provided as an unsigned int made by make_4delim() and match up to 4 different
280
* delimiters. Delimiters are stripped at the beginning and end of the pattern.
282
static int match_word(struct acl_test *test, struct acl_pattern *pattern, unsigned int delimiters)
284
int may_match, icase;
290
ps = pattern->ptr.str;
292
while (pl > 0 && is_delimiter(*ps, delimiters)) {
297
while (pl > 0 && is_delimiter(ps[pl - 1], delimiters))
304
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
305
end = test->ptr + test->len - pl;
306
for (c = test->ptr; c <= end; c++) {
307
if (is_delimiter(*c, delimiters)) {
316
if ((tolower(*c) == tolower(*ps)) &&
317
(strncasecmp(ps, c, pl) == 0) &&
318
(c == end || is_delimiter(c[pl], delimiters)))
322
(strncmp(ps, c, pl) == 0) &&
323
(c == end || is_delimiter(c[pl], delimiters)))
331
/* Checks that the pattern is included inside the tested string, but enclosed
332
* between the delimiters '?' or '/' or at the beginning or end of the string.
333
* Delimiters at the beginning or end of the pattern are ignored.
335
int acl_match_dir(struct acl_test *test, struct acl_pattern *pattern)
337
return match_word(test, pattern, make_4delim('/', '?', '?', '?'));
340
/* Checks that the pattern is included inside the tested string, but enclosed
341
* between the delmiters '/', '?', '.' or ":" or at the beginning or end of
342
* the string. Delimiters at the beginning or end of the pattern are ignored.
344
int acl_match_dom(struct acl_test *test, struct acl_pattern *pattern)
346
return match_word(test, pattern, make_4delim('/', '?', '.', ':'));
349
/* Checks that the integer in <test> is included between min and max */
350
int acl_match_int(struct acl_test *test, struct acl_pattern *pattern)
352
if ((!pattern->val.range.min_set || pattern->val.range.min <= test->i) &&
353
(!pattern->val.range.max_set || test->i <= pattern->val.range.max))
358
/* Checks that the length of the pattern in <test> is included between min and max */
359
int acl_match_len(struct acl_test *test, struct acl_pattern *pattern)
361
if ((!pattern->val.range.min_set || pattern->val.range.min <= test->len) &&
362
(!pattern->val.range.max_set || test->len <= pattern->val.range.max))
367
int acl_match_ip(struct acl_test *test, struct acl_pattern *pattern)
371
if (test->i != AF_INET)
374
s = (void *)test->ptr;
375
if (((s->s_addr ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
380
/* Lookup an IPv4 address in the expression's pattern tree using the longest
381
* match method. The node is returned if it exists, otherwise NULL.
383
void *acl_lookup_ip(struct acl_test *test, struct acl_expr *expr)
387
if (test->i != AF_INET)
390
s = (void *)test->ptr;
392
return ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
395
/* Parse a string. It is allocated and duplicated. */
396
int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque)
402
if (pattern->flags & ACL_PAT_F_TREE_OK) {
403
/* we're allowed to put the data in a tree whose root is pointed
406
struct ebmb_node *node;
408
node = calloc(1, sizeof(*node) + len + 1);
411
memcpy(node->key, *text, len + 1);
412
if (ebst_insert(pattern->val.tree, node) != node)
413
free(node); /* was a duplicate */
414
pattern->flags |= ACL_PAT_F_TREE; /* this pattern now contains a tree */
418
pattern->ptr.str = strdup(*text);
419
if (!pattern->ptr.str)
425
/* Parse and concatenate all further strings into one. */
427
acl_parse_strcat(const char **text, struct acl_pattern *pattern, int *opaque)
433
for (i = 0; *text[i]; i++)
434
len += strlen(text[i])+1;
436
pattern->ptr.str = s = calloc(1, len);
437
if (!pattern->ptr.str)
440
for (i = 0; *text[i]; i++)
441
s += sprintf(s, i?" %s":"%s", text[i]);
448
/* Free data allocated by acl_parse_reg */
449
static void acl_free_reg(void *ptr) {
451
regfree((regex_t *)ptr);
454
/* Parse a regex. It is allocated. */
455
int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque)
460
preg = calloc(1, sizeof(regex_t));
465
icase = (pattern->flags & ACL_PAT_F_IGNORE_CASE) ? REG_ICASE : 0;
466
if (regcomp(preg, *text, REG_EXTENDED | REG_NOSUB | icase) != 0) {
471
pattern->ptr.reg = preg;
472
pattern->freeptrbuf = &acl_free_reg;
476
/* Parse a range of positive integers delimited by either ':' or '-'. If only
477
* one integer is read, it is set as both min and max. An operator may be
478
* specified as the prefix, among this list of 5 :
480
* 0:eq, 1:gt, 2:ge, 3:lt, 4:le
482
* The default operator is "eq". It supports range matching. Ranges are
483
* rejected for other operators. The operator may be changed at any time.
484
* The operator is stored in the 'opaque' argument.
487
int acl_parse_int(const char **text, struct acl_pattern *pattern, int *opaque)
490
unsigned int j, last, skip = 0;
491
const char *ptr = *text;
494
while (!isdigit((unsigned char)*ptr)) {
495
if (strcmp(ptr, "eq") == 0) *opaque = 0;
496
else if (strcmp(ptr, "gt") == 0) *opaque = 1;
497
else if (strcmp(ptr, "ge") == 0) *opaque = 2;
498
else if (strcmp(ptr, "lt") == 0) *opaque = 3;
499
else if (strcmp(ptr, "le") == 0) *opaque = 4;
510
if ((j == '-' || j == ':') && !last) {
512
pattern->val.range.min = i;
518
// also catches the terminating zero
524
if (last && *opaque >= 1 && *opaque <= 4)
525
/* having a range with a min or a max is absurd */
529
pattern->val.range.min = i;
530
pattern->val.range.max = i;
534
pattern->val.range.min_set = 1;
535
pattern->val.range.max_set = 1;
538
pattern->val.range.min++; /* gt = ge + 1 */
540
pattern->val.range.min_set = 1;
541
pattern->val.range.max_set = 0;
544
pattern->val.range.max--; /* lt = le - 1 */
546
pattern->val.range.min_set = 0;
547
pattern->val.range.max_set = 1;
553
/* Parse a range of positive 2-component versions delimited by either ':' or
554
* '-'. The version consists in a major and a minor, both of which must be
555
* smaller than 65536, because internally they will be represented as a 32-bit
557
* If only one version is read, it is set as both min and max. Just like for
558
* pure integers, an operator may be specified as the prefix, among this list
561
* 0:eq, 1:gt, 2:ge, 3:lt, 4:le
563
* The default operator is "eq". It supports range matching. Ranges are
564
* rejected for other operators. The operator may be changed at any time.
565
* The operator is stored in the 'opaque' argument. This allows constructs
566
* such as the following one :
568
* acl obsolete_ssl ssl_req_proto lt 3
569
* acl unsupported_ssl ssl_req_proto gt 3.1
570
* acl valid_ssl ssl_req_proto 3.0-3.1
573
int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, int *opaque)
576
unsigned int j, last, skip = 0;
577
const char *ptr = *text;
580
while (!isdigit((unsigned char)*ptr)) {
581
if (strcmp(ptr, "eq") == 0) *opaque = 0;
582
else if (strcmp(ptr, "gt") == 0) *opaque = 1;
583
else if (strcmp(ptr, "ge") == 0) *opaque = 2;
584
else if (strcmp(ptr, "lt") == 0) *opaque = 3;
585
else if (strcmp(ptr, "le") == 0) *opaque = 4;
603
if ((j == '-' || j == ':') && !last) {
607
pattern->val.range.min = i;
613
// also catches the terminating zero
615
i = (i & 0xFFFF0000) + (i & 0xFFFF) * 10;
619
/* if we only got a major version, let's shift it now */
623
if (last && *opaque >= 1 && *opaque <= 4)
624
/* having a range with a min or a max is absurd */
628
pattern->val.range.min = i;
629
pattern->val.range.max = i;
633
pattern->val.range.min_set = 1;
634
pattern->val.range.max_set = 1;
637
pattern->val.range.min++; /* gt = ge + 1 */
639
pattern->val.range.min_set = 1;
640
pattern->val.range.max_set = 0;
643
pattern->val.range.max--; /* lt = le - 1 */
645
pattern->val.range.min_set = 0;
646
pattern->val.range.max_set = 1;
652
/* Parse an IP address and an optional mask in the form addr[/mask].
653
* The addr may either be an IPv4 address or a hostname. The mask
654
* may either be a dotted mask or a number of bits. Returns 1 if OK,
657
int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque)
659
struct eb_root *tree = NULL;
660
if (pattern->flags & ACL_PAT_F_TREE_OK)
661
tree = pattern->val.tree;
663
if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask)) {
664
unsigned int mask = ntohl(pattern->val.ipv4.mask.s_addr);
665
struct ebmb_node *node;
666
/* check if the mask is contiguous so that we can insert the
667
* network into the tree. A continuous mask has only ones on
668
* the left. This means that this mask + its lower bit added
669
* once again is null.
671
if (mask + (mask & -mask) == 0 && tree) {
672
mask = mask ? 33 - flsnz(mask & -mask) : 0; /* equals cidr value */
673
/* FIXME: insert <addr>/<mask> into the tree here */
674
node = calloc(1, sizeof(*node) + 4); /* reserve 4 bytes for IPv4 address */
677
memcpy(node->key, &pattern->val.ipv4.addr, 4); /* network byte order */
678
node->node.pfx = mask;
679
if (ebmb_insert_prefix(tree, node, 4) != node)
680
free(node); /* was a duplicate */
681
pattern->flags |= ACL_PAT_F_TREE;
41
/* input values are 0 or 3, output is the same */
42
static inline enum acl_test_res pat2acl(struct pattern *pat)
744
/* NB: does nothing if <pat> is NULL */
745
static void free_pattern(struct acl_pattern *pat)
752
pat->freeptrbuf(pat->ptr.ptr);
760
static void free_pattern_list(struct list *head)
762
struct acl_pattern *pat, *tmp;
763
list_for_each_entry_safe(pat, tmp, head, list)
767
static void free_pattern_tree(struct eb_root *root)
769
struct eb_node *node, *next;
770
node = eb_first(root);
772
next = eb_next(node);
779
105
static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
781
free_pattern_list(&expr->patterns);
782
free_pattern_tree(&expr->pattern_tree);
783
LIST_INIT(&expr->patterns);
784
if (expr->arg_len && expr->arg.str)
109
pattern_prune(&expr->pat);
111
for (arg = expr->smp->arg_p; arg; arg++) {
112
if (arg->type == ARGT_STOP)
114
if (arg->type == ARGT_STR || arg->unresolved) {
115
free(arg->data.str.str);
116
arg->data.str.str = NULL;
121
if (expr->smp->arg_p != empty_arg_list)
122
free(expr->smp->arg_p);
790
static int acl_read_patterns_from_file( struct acl_keyword *aclkw,
791
struct acl_expr *expr,
792
const char *filename, int patflags)
797
struct acl_pattern *pattern;
801
file = fopen(filename, "r");
805
/* now parse all patterns. The file may contain only one pattern per
806
* line. If the line contains spaces, they will be part of the pattern.
807
* The pattern stops at the first CR, LF or EOF encountered.
812
while (fgets(trash, trashlen, file) != NULL) {
815
/* ignore lines beginning with a dash */
819
/* strip leading spaces and tabs */
820
while (*c == ' ' || *c == '\t')
825
while (*c && *c != '\n' && *c != '\r')
829
/* empty lines are ignored too */
833
/* we keep the previous pattern along iterations as long as it's not used */
835
pattern = (struct acl_pattern *)malloc(sizeof(*pattern));
839
memset(pattern, 0, sizeof(*pattern));
840
pattern->flags = patflags;
842
if ((aclkw->requires & ACL_MAY_LOOKUP) && !(pattern->flags & ACL_PAT_F_IGNORE_CASE)) {
843
/* we pre-set the data pointer to the tree's head so that functions
844
* which are able to insert in a tree know where to do that.
846
pattern->flags |= ACL_PAT_F_TREE_OK;
847
pattern->val.tree = &expr->pattern_tree;
850
if (!aclkw->parse(args, pattern, &opaque))
851
goto out_free_pattern;
853
/* if the parser did not feed the tree, let's chain the pattern to the list */
854
if (!(pattern->flags & ACL_PAT_F_TREE)) {
855
LIST_ADDQ(&expr->patterns, &pattern->list);
856
pattern = NULL; /* get a new one */
860
ret = 1; /* success */
863
free_pattern(pattern);
869
/* Parse an ACL expression starting at <args>[0], and return it.
126
/* Parse an ACL expression starting at <args>[0], and return it. If <err> is
127
* not NULL, it will be filled with a pointer to an error message in case of
128
* error. This pointer must be freeable or NULL. <al> is an arg_list serving
129
* as a list head to report missing dependencies.
870
131
* Right now, the only accepted syntax is :
871
132
* <subject> [<value>...]
873
struct acl_expr *parse_acl_expr(const char **args)
134
struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *al,
135
const char *file, int line)
875
__label__ out_return, out_free_expr, out_free_pattern;
137
__label__ out_return, out_free_expr;
876
138
struct acl_expr *expr;
877
139
struct acl_keyword *aclkw;
878
struct acl_pattern *pattern;
879
int opaque, patflags;
142
struct sample_expr *smp = NULL;
148
unsigned long prev_type;
151
int operator = STD_OP_EQ;
153
int contain_colon, have_dot;
155
signed long long value, minor;
156
/* The following buffer contain two numbers, a ':' separator and the final \0. */
157
char buffer[NB_LLMAX_STR + 1 + NB_LLMAX_STR + 1];
162
struct pattern_expr *pattern_expr;
165
/* First, we look for an ACL keyword. And if we don't find one, then
166
* we look for a sample fetch expression starting with a sample fetch
170
al->ctx = ARGC_ACL; // to report errors while resolving args late
882
174
aclkw = find_acl_kw(args[0]);
883
if (!aclkw || !aclkw->parse)
176
/* OK we have a real ACL keyword */
178
/* build new sample expression for this ACL */
179
smp = calloc(1, sizeof(struct sample_expr));
181
memprintf(err, "out of memory when parsing ACL expression");
184
LIST_INIT(&(smp->conv_exprs));
185
smp->fetch = aclkw->smp;
186
smp->arg_p = empty_arg_list;
188
/* look for the begining of the subject arguments */
189
for (arg = args[0]; *arg && *arg != '(' && *arg != ','; arg++);
193
/* look for the end of this term and skip the opening parenthesis */
195
while (*endt && *endt != ')')
198
memprintf(err, "missing closing ')' after arguments to ACL keyword '%s'", aclkw->kw);
203
/* At this point, we have :
204
* - args[0] : beginning of the keyword
205
* - arg : end of the keyword, first character not part of keyword
206
* nor the opening parenthesis (so first character of args
208
* - endt : end of the term (=arg or last parenthesis if args are present)
210
nbargs = make_arg_list(arg, endt - arg, smp->fetch->arg_mask, &smp->arg_p,
211
err, NULL, NULL, al);
213
/* note that make_arg_list will have set <err> here */
214
memprintf(err, "ACL keyword '%s' : %s", aclkw->kw, *err);
219
smp->arg_p = empty_arg_list;
221
else if (smp->fetch->val_args && !smp->fetch->val_args(smp->arg_p, err)) {
222
/* invalid keyword argument, error must have been
225
memprintf(err, "in argument to '%s', %s", aclkw->kw, *err);
230
/* look for the begining of the converters list. Those directly attached
231
* to the ACL keyword are found just after <arg> which points to the comma.
233
prev_type = smp->fetch->out_type;
235
struct sample_conv *conv;
236
struct sample_conv_expr *conv_expr;
238
if (*arg == ')') /* skip last closing parenthesis */
241
if (*arg && *arg != ',') {
243
memprintf(err, "ACL keyword '%s' : missing comma after conv keyword '%s'.",
246
memprintf(err, "ACL keyword '%s' : missing comma after fetch keyword.",
251
while (*arg == ',') /* then trailing commas */
254
begw = arg; /* start of conv keyword */
257
/* none ? end of converters */
260
for (endw = begw; *endw && *endw != '(' && *endw != ','; endw++);
263
ckw = my_strndup(begw, endw - begw);
265
conv = find_sample_conv(begw, endw - begw);
267
/* Unknown converter method */
268
memprintf(err, "ACL keyword '%s' : unknown conv method '%s'.",
275
/* look for the end of this term */
276
while (*arg && *arg != ')')
279
memprintf(err, "ACL keyword '%s' : syntax error: missing ')' after conv keyword '%s'.",
285
if (conv->in_type >= SMP_TYPES || conv->out_type >= SMP_TYPES) {
286
memprintf(err, "ACL keyword '%s' : returns type of conv method '%s' is unknown.",
291
/* If impossible type conversion */
292
if (!sample_casts[prev_type][conv->in_type]) {
293
memprintf(err, "ACL keyword '%s' : conv method '%s' cannot be applied.",
298
prev_type = conv->out_type;
299
conv_expr = calloc(1, sizeof(struct sample_conv_expr));
303
LIST_ADDQ(&(smp->conv_exprs), &(conv_expr->list));
304
conv_expr->conv = conv;
309
if (!conv->arg_mask) {
310
memprintf(err, "ACL keyword '%s' : conv method '%s' does not support any args.",
315
al->kw = smp->fetch->kw;
316
al->conv = conv_expr->conv->kw;
317
if (make_arg_list(endw + 1, arg - endw - 1, conv->arg_mask, &conv_expr->arg_p, err, NULL, &err_arg, al) < 0) {
318
memprintf(err, "ACL keyword '%s' : invalid arg %d in conv method '%s' : %s.",
319
aclkw->kw, err_arg+1, ckw, *err);
323
if (!conv_expr->arg_p)
324
conv_expr->arg_p = empty_arg_list;
326
if (conv->val_args && !conv->val_args(conv_expr->arg_p, conv, file, line, err)) {
327
memprintf(err, "ACL keyword '%s' : invalid args in conv method '%s' : %s.",
328
aclkw->kw, ckw, *err);
332
else if (ARGM(conv->arg_mask)) {
333
memprintf(err, "ACL keyword '%s' : missing args for conv method '%s'.",
340
/* This is not an ACL keyword, so we hope this is a sample fetch
341
* keyword that we're going to transparently use as an ACL. If
342
* so, we retrieve a completely parsed expression with args and
343
* convs already done.
345
smp = sample_parse_expr((char **)args, &idx, file, line, err, al);
347
memprintf(err, "%s in ACL expression '%s'", *err, *args);
886
352
expr = (struct acl_expr *)calloc(1, sizeof(*expr));
354
memprintf(err, "out of memory when parsing ACL expression");
892
LIST_INIT(&expr->patterns);
893
expr->pattern_tree = EB_ROOT_UNIQUE;
894
expr->arg.str = NULL;
897
arg = strchr(args[0], '(');
900
/* there is an argument in the form "subject(arg)" */
902
end = strchr(arg, ')');
905
arg2 = my_strndup(arg, end - arg);
908
expr->arg_len = end - arg;
909
expr->arg.str = arg2;
358
pattern_init_head(&expr->pat);
360
expr->kw = aclkw ? aclkw->kw : smp->fetch->kw;
361
expr->pat.parse = aclkw ? aclkw->parse : NULL;
362
expr->pat.index = aclkw ? aclkw->index : NULL;
363
expr->pat.match = aclkw ? aclkw->match : NULL;
364
expr->pat.delete = aclkw ? aclkw->delete : NULL;
365
expr->pat.prune = aclkw ? aclkw->prune : NULL;
366
expr->pat.expect_type = smp->fetch->out_type;
370
/* Fill NULL pointers with values provided by the pattern.c arrays */
372
if (!expr->pat.parse)
373
expr->pat.parse = pat_parse_fcts[aclkw->match_type];
375
if (!expr->pat.index)
376
expr->pat.index = pat_index_fcts[aclkw->match_type];
378
if (!expr->pat.match)
379
expr->pat.match = pat_match_fcts[aclkw->match_type];
381
if (!expr->pat.delete)
382
expr->pat.delete = pat_delete_fcts[aclkw->match_type];
384
if (!expr->pat.prune)
385
expr->pat.prune = pat_prune_fcts[aclkw->match_type];
388
if (!expr->pat.parse) {
389
/* some types can be automatically converted */
391
switch (expr->smp ? expr->smp->fetch->out_type : aclkw->smp->out_type) {
393
expr->pat.parse = pat_parse_fcts[PAT_MATCH_BOOL];
394
expr->pat.index = pat_index_fcts[PAT_MATCH_BOOL];
395
expr->pat.match = pat_match_fcts[PAT_MATCH_BOOL];
396
expr->pat.delete = pat_delete_fcts[PAT_MATCH_BOOL];
397
expr->pat.prune = pat_prune_fcts[PAT_MATCH_BOOL];
398
expr->pat.expect_type = pat_match_types[PAT_MATCH_BOOL];
402
expr->pat.parse = pat_parse_fcts[PAT_MATCH_INT];
403
expr->pat.index = pat_index_fcts[PAT_MATCH_INT];
404
expr->pat.match = pat_match_fcts[PAT_MATCH_INT];
405
expr->pat.delete = pat_delete_fcts[PAT_MATCH_INT];
406
expr->pat.prune = pat_prune_fcts[PAT_MATCH_INT];
407
expr->pat.expect_type = pat_match_types[PAT_MATCH_INT];
411
expr->pat.parse = pat_parse_fcts[PAT_MATCH_IP];
412
expr->pat.index = pat_index_fcts[PAT_MATCH_IP];
413
expr->pat.match = pat_match_fcts[PAT_MATCH_IP];
414
expr->pat.delete = pat_delete_fcts[PAT_MATCH_IP];
415
expr->pat.prune = pat_prune_fcts[PAT_MATCH_IP];
416
expr->pat.expect_type = pat_match_types[PAT_MATCH_IP];
419
expr->pat.parse = pat_parse_fcts[PAT_MATCH_STR];
420
expr->pat.index = pat_index_fcts[PAT_MATCH_STR];
421
expr->pat.match = pat_match_fcts[PAT_MATCH_STR];
422
expr->pat.delete = pat_delete_fcts[PAT_MATCH_STR];
423
expr->pat.prune = pat_prune_fcts[PAT_MATCH_STR];
424
expr->pat.expect_type = pat_match_types[PAT_MATCH_STR];
429
/* Additional check to protect against common mistakes */
430
cur_type = smp_expr_output_type(expr->smp);
431
if (expr->pat.parse && cur_type != SMP_T_BOOL && !*args[1]) {
432
Warning("parsing acl keyword '%s' :\n"
433
" no pattern to match against were provided, so this ACL will never match.\n"
434
" If this is what you intended, please add '--' to get rid of this warning.\n"
435
" If you intended to match only for existence, please use '-m found'.\n"
436
" If you wanted to force an int to match as a bool, please use '-m bool'.\n"
914
443
/* check for options before patterns. Supported options are :
915
444
* -i : ignore case for all patterns by default
916
445
* -f : read patterns from those files
446
* -m : force matching method (must be used before -f)
447
* -M : load the file as map file
448
* -u : force the unique id of the acl
917
449
* -- : everything after this is not an option
920
454
while (**args == '-') {
921
if ((*args)[1] == 'i')
922
patflags |= ACL_PAT_F_IGNORE_CASE;
923
else if ((*args)[1] == 'f') {
924
if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE))
928
else if ((*args)[1] == '-') {
455
if (strcmp(*args, "-i") == 0)
456
patflags |= PAT_MF_IGNORE_CASE;
457
else if (strcmp(*args, "-n") == 0)
458
patflags |= PAT_MF_NO_DNS;
459
else if (strcmp(*args, "-u") == 0) {
460
unique_id = strtol(args[1], &error, 10);
461
if (*error != '\0') {
462
memprintf(err, "the argument of -u must be an integer");
466
/* Check if this id is really unique. */
467
if (pat_ref_lookupid(unique_id)) {
468
memprintf(err, "the id is already used");
474
else if (strcmp(*args, "-f") == 0) {
475
if (!expr->pat.parse) {
476
memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
480
if (!pattern_read_from_file(&expr->pat, PAT_REF_ACL, args[1], patflags, load_as_map, err, file, line))
485
else if (strcmp(*args, "-m") == 0) {
489
memprintf(err, "'-m' must only be specified before patterns and files in parsing ACL expression");
493
idx = pat_find_match_name(args[1]);
495
memprintf(err, "unknown matching method '%s' when parsing ACL expression", args[1]);
499
/* Note: -m found is always valid, bool/int are compatible, str/bin/reg/len are compatible */
500
if (!sample_casts[cur_type][pat_match_types[idx]]) {
501
memprintf(err, "matching method '%s' cannot be used with fetch keyword '%s'", args[1], expr->kw);
504
expr->pat.parse = pat_parse_fcts[idx];
505
expr->pat.index = pat_index_fcts[idx];
506
expr->pat.match = pat_match_fcts[idx];
507
expr->pat.delete = pat_delete_fcts[idx];
508
expr->pat.prune = pat_prune_fcts[idx];
509
expr->pat.expect_type = pat_match_types[idx];
512
else if (strcmp(*args, "-M") == 0) {
515
else if (strcmp(*args, "--") == 0) {
520
memprintf(err, "'%s' is not a valid ACL option. Please use '--' before any pattern beginning with a '-'", args[0]);
527
if (!expr->pat.parse) {
528
memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
532
/* Create displayed reference */
533
snprintf(trash.str, trash.size, "acl '%s' file '%s' line %d", expr->kw, file, line);
534
trash.str[trash.size - 1] = '\0';
536
/* Create new patern reference. */
537
ref = pat_ref_newid(unique_id, trash.str, PAT_REF_ACL);
539
memprintf(err, "memory error");
543
/* Create new pattern expression associated to this reference. */
544
pattern_expr = pattern_new_expr(&expr->pat, ref, err);
548
/* Copy the pattern matching and indexing flags. */
549
pattern_expr->mflags = patflags;
937
551
/* now parse all patterns */
941
pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
555
/* Compatibility layer. Each pattern can parse only one string per pattern,
556
* but the pat_parser_int() and pat_parse_dotted_ver() parsers were need
557
* optionnaly two operators. The first operator is the match method: eq,
558
* le, lt, ge and gt. pat_parse_int() and pat_parse_dotted_ver() functions
559
* can have a compatibility syntax based on ranges:
563
* "eq x" -> "x" or "x:x"
565
* "lt x" -> ":y" (with y = x - 1)
567
* "gt x" -> "y:" (with y = x + 1)
569
* pat_parse_dotted_ver():
571
* "eq x.y" -> "x.y" or "x.y:x.y"
573
* "lt x.y" -> ":w.z" (with w.z = x.y - 1)
575
* "gt x.y" -> "w.z:" (with w.z = x.y + 1)
577
* If y is not present, assume that is "0".
579
* The syntax eq, le, lt, ge and gt are proper to the acl syntax. The
580
* following block of code detect the operator, and rewrite each value
581
* in parsable string.
583
if (expr->pat.parse == pat_parse_int ||
584
expr->pat.parse == pat_parse_dotted_ver) {
585
/* Check for operator. If the argument is operator, memorise it and
586
* continue to the next argument.
588
op = get_std_op(arg);
595
/* Check if the pattern contain ':' or '-' character. */
596
contain_colon = (strchr(arg, ':') || strchr(arg, '-'));
598
/* If the pattern contain ':' or '-' character, give it to the parser as is.
599
* If no contain ':' and operator is STD_OP_EQ, give it to the parser as is.
600
* In other case, try to convert the value according with the operator.
602
if (!contain_colon && operator != STD_OP_EQ) {
603
/* Search '.' separator. */
604
dot = strchr(arg, '.');
608
dot = arg + strlen(arg);
613
/* convert the integer minor part for the pat_parse_dotted_ver() function. */
614
if (expr->pat.parse == pat_parse_dotted_ver && have_dot) {
615
if (strl2llrc(dot+1, strlen(dot+1), &minor) != 0) {
616
memprintf(err, "'%s' is neither a number nor a supported operator", arg);
619
if (minor >= 65536) {
620
memprintf(err, "'%s' contains too large a minor value", arg);
625
/* convert the integer value for the pat_parse_int() function, and the
626
* integer major part for the pat_parse_dotted_ver() function.
628
if (strl2llrc(arg, dot - arg, &value) != 0) {
629
memprintf(err, "'%s' is neither a number nor a supported operator", arg);
632
if (expr->pat.parse == pat_parse_dotted_ver) {
633
if (value >= 65536) {
634
memprintf(err, "'%s' contains too large a major value", arg);
637
value = (value << 16) | (minor & 0xffff);
642
case STD_OP_EQ: /* this case is not possible. */
643
memprintf(err, "internal error");
647
value++; /* gt = ge + 1 */
650
if (expr->pat.parse == pat_parse_int)
651
snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, "%lld:", value);
653
snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, "%lld.%lld:",
654
value >> 16, value & 0xffff);
659
value--; /* lt = le - 1 */
662
if (expr->pat.parse == pat_parse_int)
663
snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, ":%lld", value);
665
snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, ":%lld.%lld",
666
value >> 16, value & 0xffff);
673
/* Add sample to the reference, and try to compile it fior each pattern
676
if (!pat_ref_add(ref, arg, NULL, err))
943
677
goto out_free_expr;
944
pattern->flags = patflags;
946
ret = aclkw->parse(args, pattern, &opaque);
948
goto out_free_pattern;
949
LIST_ADDQ(&expr->patterns, &pattern->list);
956
free_pattern(pattern);
958
684
prune_acl_expr(expr);
1442
1220
list_for_each_entry(suite, &cond->suites, list) {
1443
1221
list_for_each_entry(term, &suite->terms, list) {
1444
1222
acl = term->acl;
1445
if (acl->requires & require)
1223
if (!(acl->val & where))
1230
/* Returns a pointer to the first ACL and its first keyword to conflict with
1231
* usage at place <where> which is one of the SMP_VAL_* bits indicating a check
1232
* place. Returns true if a conflict is found, with <acl> and <kw> set (if non
1233
* null), or false if not conflict is found. The first useless keyword is
1236
int acl_cond_kw_conflicts(const struct acl_cond *cond, unsigned int where, struct acl const **acl, char const **kw)
1238
struct acl_term_suite *suite;
1239
struct acl_term *term;
1240
struct acl_expr *expr;
1242
list_for_each_entry(suite, &cond->suites, list) {
1243
list_for_each_entry(term, &suite->terms, list) {
1244
list_for_each_entry(expr, &term->acl->expr, list) {
1245
if (!(expr->smp->fetch->val & where)) {
1453
1259
* Find targets for userlist and groups in acl. Function returns the number
1454
* of errors or OK if everything is fine.
1260
* of errors or OK if everything is fine. It must be called only once sample
1261
* fetch arguments have been resolved (after smp_resolve_args()).
1457
acl_find_targets(struct proxy *p)
1263
int acl_find_targets(struct proxy *p)
1460
1266
struct acl *acl;
1461
1267
struct acl_expr *expr;
1462
struct acl_pattern *pattern;
1463
struct userlist *ul;
1268
struct pattern_list *pattern;
1464
1269
int cfgerr = 0;
1270
struct pattern_expr_list *pexp;
1466
1272
list_for_each_entry(acl, &p->acl, list) {
1467
1273
list_for_each_entry(expr, &acl->expr, list) {
1468
if (strcmp(expr->kw->kw, "srv_is_up") == 0) {
1471
char *pname, *sname;
1473
if (!expr->arg.str || !*expr->arg.str) {
1474
Alert("proxy %s: acl %s %s(): missing server name.\n",
1475
p->id, acl->name, expr->kw->kw);
1480
pname = expr->arg.str;
1481
sname = strrchr(pname, '/');
1492
px = findproxy(pname, PR_CAP_BE);
1494
Alert("proxy %s: acl %s %s(): unable to find proxy '%s'.\n",
1495
p->id, acl->name, expr->kw->kw, pname);
1501
srv = findserver(px, sname);
1503
Alert("proxy %s: acl %s %s(): unable to find server '%s'.\n",
1504
p->id, acl->name, expr->kw->kw, sname);
1509
free(expr->arg.str);
1511
expr->arg.srv = srv;
1515
if (strstr(expr->kw->kw, "http_auth") == expr->kw->kw) {
1517
if (!expr->arg.str || !*expr->arg.str) {
1518
Alert("proxy %s: acl %s %s(): missing userlist name.\n",
1519
p->id, acl->name, expr->kw->kw);
1524
if (p->uri_auth && p->uri_auth->userlist &&
1525
!strcmp(p->uri_auth->userlist->name, expr->arg.str))
1526
ul = p->uri_auth->userlist;
1528
ul = auth_find_userlist(expr->arg.str);
1531
Alert("proxy %s: acl %s %s(%s): unable to find userlist.\n",
1532
p->id, acl->name, expr->kw->kw, expr->arg.str);
1542
if (!strcmp(expr->kw->kw, "http_auth_group")) {
1544
if (LIST_ISEMPTY(&expr->patterns)) {
1274
if (!strcmp(expr->kw, "http_auth_group")) {
1275
/* Note: the ARGT_USR argument may only have been resolved earlier
1276
* by smp_resolve_args().
1278
if (expr->smp->arg_p->unresolved) {
1279
Alert("Internal bug in proxy %s: %sacl %s %s() makes use of unresolved userlist '%s'. Please report this.\n",
1280
p->id, *acl->name ? "" : "anonymous ", acl->name, expr->kw, expr->smp->arg_p->data.str.str);
1285
if (LIST_ISEMPTY(&expr->pat.head)) {
1545
1286
Alert("proxy %s: acl %s %s(): no groups specified.\n",
1546
p->id, acl->name, expr->kw->kw);
1287
p->id, acl->name, expr->kw);
1551
list_for_each_entry(pattern, &expr->patterns, list) {
1552
pattern->val.group_mask = auth_resolve_groups(expr->arg.ul, pattern->ptr.str);
1554
free(pattern->ptr.str);
1555
pattern->ptr.str = NULL;
1558
if (!pattern->val.group_mask) {
1559
Alert("proxy %s: acl %s %s(): invalid group(s).\n",
1560
p->id, acl->name, expr->kw->kw);
1292
/* For each pattern, check if the group exists. */
1293
list_for_each_entry(pexp, &expr->pat.head, list) {
1294
if (LIST_ISEMPTY(&pexp->expr->patterns)) {
1295
Alert("proxy %s: acl %s %s(): no groups specified.\n",
1296
p->id, acl->name, expr->kw);
1301
list_for_each_entry(pattern, &pexp->expr->patterns, list) {
1302
/* this keyword only has one argument */
1303
if (!check_group(expr->smp->arg_p->data.usr, pattern->pat.ptr.str)) {
1304
Alert("proxy %s: acl %s %s(): invalid group '%s'.\n",
1305
p->id, acl->name, expr->kw, pattern->pat.ptr.str);