~ubuntu-branches/debian/stretch/haproxy/stretch

« back to all changes in this revision

Viewing changes to src/acl.c

  • Committer: Package Import Robot
  • Author(s): Apollon Oikonomopoulos
  • Date: 2014-06-20 11:05:17 UTC
  • mfrom: (1.1.15) (15.1.12 experimental)
  • Revision ID: package-import@ubuntu.com-20140620110517-u6q5p9kyy2f3ozw9
Tags: 1.5.0-1
* New upstream stable series. Notable changes since the 1.4 series:
  + Native SSL support on both sides with SNI/NPN/ALPN and OCSP stapling.
  + IPv6 and UNIX sockets are supported everywhere
  + End-to-end HTTP keep-alive for better support of NTLM and improved
    efficiency in static farms
  + HTTP/1.1 response compression (deflate, gzip) to save bandwidth
  + PROXY protocol versions 1 and 2 on both sides
  + Data sampling on everything in request or response, including payload
  + ACLs can use any matching method with any input sample
  + Maps and dynamic ACLs updatable from the CLI
  + Stick-tables support counters to track activity on any input sample
  + Custom format for logs, unique-id, header rewriting, and redirects
  + Improved health checks (SSL, scripted TCP, check agent, ...)
  + Much more scalable configuration supports hundreds of thousands of
    backends and certificates without sweating

* Upload to unstable, merge all 1.5 work from experimental. Most important
  packaging changes since 1.4.25-1 include:
  + systemd support.
  + A more sane default config file.
  + Zero-downtime upgrades between 1.5 releases by gracefully reloading
    HAProxy during upgrades.
  + HTML documentation shipped in the haproxy-doc package.
  + kqueue support for kfreebsd.

* Packaging changes since 1.5~dev26-2:
  + Drop patches merged upstream:
    o Fix-reference-location-in-manpage.patch
    o 0001-BUILD-stats-workaround-stupid-and-bogus-Werror-forma.patch
  + d/watch: look for stable 1.5 releases
  + systemd: respect CONFIG and EXTRAOPTS when specified in
    /etc/default/haproxy.
  + initscript: test the configuration before start or reload.
  + initscript: remove the ENABLED flag and logic.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * ACL management functions.
3
3
 *
4
 
 * Copyright 2000-2011 Willy Tarreau <w@1wt.eu>
 
4
 * Copyright 2000-2013 Willy Tarreau <w@1wt.eu>
5
5
 *
6
6
 * This program is free software; you can redistribute it and/or
7
7
 * modify it under the terms of the GNU General Public License
22
22
#include <types/global.h>
23
23
 
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>
28
33
 
29
34
#include <ebsttree.h>
30
35
 
31
 
/* The capabilities of filtering hooks describe the type of information
32
 
 * available to each of them.
33
 
 */
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,
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
 
 
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)
56
39
};
57
40
 
58
 
 
59
 
/*
60
 
 * These functions are only used for debugging complex configurations.
61
 
 */
62
 
 
63
 
/* force TRUE to be returned at the fetch level */
64
 
static int
65
 
acl_fetch_true(struct proxy *px, struct session *l4, void *l7, int dir,
66
 
               struct acl_expr *expr, struct acl_test *test)
67
 
{
68
 
        test->flags |= ACL_TEST_F_SET_RES_PASS;
69
 
        return 1;
70
 
}
71
 
 
72
 
/* wait for more data as long as possible, then return TRUE. This should be
73
 
 * used with content inspection.
74
 
 */
75
 
static int
76
 
acl_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
 
 
87
 
/* force FALSE to be returned at the fetch level */
88
 
static int
89
 
acl_fetch_false(struct proxy *px, struct session *l4, void *l7, int dir,
90
 
                struct acl_expr *expr, struct acl_test *test)
91
 
{
92
 
        test->flags |= ACL_TEST_F_SET_RES_FAIL;
93
 
        return 1;
94
 
}
95
 
 
96
 
 
97
 
/*
98
 
 * These functions are exported and may be used by any other component.
99
 
 */
100
 
 
101
 
/* ignore the current line */
102
 
int acl_parse_nothing(const char **text, struct acl_pattern *pattern, int *opaque)
103
 
{
104
 
        return 1;
105
 
}
106
 
 
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)
110
 
{
111
 
        return 1;
112
 
}
113
 
 
114
 
/* always return false */
115
 
int acl_match_nothing(struct acl_test *test, struct acl_pattern *pattern)
116
 
{
117
 
        return ACL_PAT_FAIL;
118
 
}
119
 
 
120
 
 
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)
123
 
{
124
 
        int icase;
125
 
 
126
 
        if (pattern->len != test->len)
127
 
                return ACL_PAT_FAIL;
128
 
 
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))
132
 
                return ACL_PAT_PASS;
133
 
        return ACL_PAT_FAIL;
134
 
}
135
 
 
136
 
/* Lookup a string in the expression's pattern tree. The node is returned if it
137
 
 * exists, otherwise NULL.
138
 
 */
139
 
void *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
 
 
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.
159
 
 */
160
 
int 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)
170
 
                        return ACL_PAT_FAIL;
171
 
 
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)
185
 
                ret = ACL_PAT_PASS;
186
 
        else
187
 
                ret = ACL_PAT_FAIL;
188
 
 
189
 
        test->ptr[test->len] = old_char;
190
 
        return ret;
191
 
}
192
 
 
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)
195
 
{
196
 
        int icase;
197
 
 
198
 
        if (pattern->len > test->len)
199
 
                return ACL_PAT_FAIL;
200
 
 
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))
204
 
                return ACL_PAT_FAIL;
205
 
        return ACL_PAT_PASS;
206
 
}
207
 
 
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)
210
 
{
211
 
        int icase;
212
 
 
213
 
        if (pattern->len > test->len)
214
 
                return ACL_PAT_FAIL;
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))
218
 
                return ACL_PAT_FAIL;
219
 
        return ACL_PAT_PASS;
220
 
}
221
 
 
222
 
/* Checks that the pattern is included inside the tested string.
223
 
 * NB: Suboptimal, should be rewritten using a Boyer-Moore method.
224
 
 */
225
 
int acl_match_sub(struct acl_test *test, struct acl_pattern *pattern)
226
 
{
227
 
        int icase;
228
 
        char *end;
229
 
        char *c;
230
 
 
231
 
        if (pattern->len > test->len)
232
 
                return ACL_PAT_FAIL;
233
 
 
234
 
        end = test->ptr + test->len - pattern->len;
235
 
        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)
241
 
                                return ACL_PAT_PASS;
242
 
                }
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)
248
 
                                return ACL_PAT_PASS;
249
 
                }
250
 
        }
251
 
        return ACL_PAT_FAIL;
252
 
}
253
 
 
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;
257
 
 *
258
 
 * To look for 4 different byte values, xor the word with those bytes and
259
 
 * then check for zero bytes:
260
 
 *
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
264
 
 */
265
 
static inline unsigned int is_delimiter(unsigned char c, unsigned int mask)
266
 
{
267
 
        mask ^= (c * 0x01010101); /* propagate the char to all 4 bytes */
268
 
        return (mask - 0x01010101) & ~mask & 0x80808080U;
269
 
}
270
 
 
271
 
static inline unsigned int make_4delim(unsigned char d1, unsigned char d2, unsigned char d3, unsigned char d4)
272
 
{
273
 
        return d1 << 24 | d2 << 16 | d3 << 8 | d4;
274
 
}
275
 
 
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.
281
 
 */
282
 
static int match_word(struct acl_test *test, struct acl_pattern *pattern, unsigned int delimiters)
283
 
{
284
 
        int may_match, icase;
285
 
        char *c, *end;
286
 
        char *ps;
287
 
        int pl;
288
 
 
289
 
        pl = pattern->len;
290
 
        ps = pattern->ptr.str;
291
 
 
292
 
        while (pl > 0 && is_delimiter(*ps, delimiters)) {
293
 
                pl--;
294
 
                ps++;
295
 
        }
296
 
 
297
 
        while (pl > 0 && is_delimiter(ps[pl - 1], delimiters))
298
 
                pl--;
299
 
 
300
 
        if (pl > test->len)
301
 
                return ACL_PAT_FAIL;
302
 
 
303
 
        may_match = 1;
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)) {
308
 
                        may_match = 1;
309
 
                        continue;
310
 
                }
311
 
 
312
 
                if (!may_match)
313
 
                        continue;
314
 
 
315
 
                if (icase) {
316
 
                        if ((tolower(*c) == tolower(*ps)) &&
317
 
                            (strncasecmp(ps, c, pl) == 0) &&
318
 
                            (c == end || is_delimiter(c[pl], delimiters)))
319
 
                                return ACL_PAT_PASS;
320
 
                } else {
321
 
                        if ((*c == *ps) &&
322
 
                            (strncmp(ps, c, pl) == 0) &&
323
 
                            (c == end || is_delimiter(c[pl], delimiters)))
324
 
                                return ACL_PAT_PASS;
325
 
                }
326
 
                may_match = 0;
327
 
        }
328
 
        return ACL_PAT_FAIL;
329
 
}
330
 
 
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.
334
 
 */
335
 
int acl_match_dir(struct acl_test *test, struct acl_pattern *pattern)
336
 
{
337
 
        return match_word(test, pattern, make_4delim('/', '?', '?', '?'));
338
 
}
339
 
 
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.
343
 
 */
344
 
int acl_match_dom(struct acl_test *test, struct acl_pattern *pattern)
345
 
{
346
 
        return match_word(test, pattern, make_4delim('/', '?', '.', ':'));
347
 
}
348
 
 
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)
351
 
{
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))
354
 
                return ACL_PAT_PASS;
355
 
        return ACL_PAT_FAIL;
356
 
}
357
 
 
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)
360
 
{
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))
363
 
                return ACL_PAT_PASS;
364
 
        return ACL_PAT_FAIL;
365
 
}
366
 
 
367
 
int acl_match_ip(struct acl_test *test, struct acl_pattern *pattern)
368
 
{
369
 
        struct in_addr *s;
370
 
 
371
 
        if (test->i != AF_INET)
372
 
                return ACL_PAT_FAIL;
373
 
 
374
 
        s = (void *)test->ptr;
375
 
        if (((s->s_addr ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
376
 
                return ACL_PAT_PASS;
377
 
        return ACL_PAT_FAIL;
378
 
}
379
 
 
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.
382
 
 */
383
 
void *acl_lookup_ip(struct acl_test *test, struct acl_expr *expr)
384
 
{
385
 
        struct in_addr *s;
386
 
 
387
 
        if (test->i != AF_INET)
388
 
                return ACL_PAT_FAIL;
389
 
 
390
 
        s = (void *)test->ptr;
391
 
 
392
 
        return ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
393
 
}
394
 
 
395
 
/* Parse a string. It is allocated and duplicated. */
396
 
int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque)
397
 
{
398
 
        int len;
399
 
 
400
 
        len  = strlen(*text);
401
 
 
402
 
        if (pattern->flags & ACL_PAT_F_TREE_OK) {
403
 
                /* we're allowed to put the data in a tree whose root is pointed
404
 
                 * to by val.tree.
405
 
                 */
406
 
                struct ebmb_node *node;
407
 
 
408
 
                node = calloc(1, sizeof(*node) + len + 1);
409
 
                if (!node)
410
 
                        return 0;
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 */
415
 
                return 1;
416
 
        }
417
 
 
418
 
        pattern->ptr.str = strdup(*text);
419
 
        if (!pattern->ptr.str)
420
 
                return 0;
421
 
        pattern->len = len;
422
 
        return 1;
423
 
}
424
 
 
425
 
/* Parse and concatenate all further strings into one. */
426
 
int
427
 
acl_parse_strcat(const char **text, struct acl_pattern *pattern, int *opaque)
428
 
{
429
 
 
430
 
        int len = 0, i;
431
 
        char *s;
432
 
 
433
 
        for (i = 0; *text[i]; i++)
434
 
                len += strlen(text[i])+1;
435
 
 
436
 
        pattern->ptr.str = s = calloc(1, len);
437
 
        if (!pattern->ptr.str)
438
 
                return 0;
439
 
 
440
 
        for (i = 0; *text[i]; i++)
441
 
                s += sprintf(s, i?" %s":"%s", text[i]);
442
 
 
443
 
        pattern->len = len;
444
 
 
445
 
        return i;
446
 
}
447
 
 
448
 
/* Free data allocated by acl_parse_reg */
449
 
static void acl_free_reg(void *ptr) {
450
 
 
451
 
        regfree((regex_t *)ptr);
452
 
}
453
 
 
454
 
/* Parse a regex. It is allocated. */
455
 
int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque)
456
 
{
457
 
        regex_t *preg;
458
 
        int icase;
459
 
 
460
 
        preg = calloc(1, sizeof(regex_t));
461
 
 
462
 
        if (!preg)
463
 
                return 0;
464
 
 
465
 
        icase = (pattern->flags & ACL_PAT_F_IGNORE_CASE) ? REG_ICASE : 0;
466
 
        if (regcomp(preg, *text, REG_EXTENDED | REG_NOSUB | icase) != 0) {
467
 
                free(preg);
468
 
                return 0;
469
 
        }
470
 
 
471
 
        pattern->ptr.reg = preg;
472
 
        pattern->freeptrbuf = &acl_free_reg;
473
 
        return 1;
474
 
}
475
 
 
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 :
479
 
 *
480
 
 *    0:eq, 1:gt, 2:ge, 3:lt, 4:le
481
 
 *
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.
485
 
 *
486
 
 */
487
 
int acl_parse_int(const char **text, struct acl_pattern *pattern, int *opaque)
488
 
{
489
 
        signed long long i;
490
 
        unsigned int j, last, skip = 0;
491
 
        const char *ptr = *text;
492
 
 
493
 
 
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;
500
 
                else
501
 
                        return 0;
502
 
 
503
 
                skip++;
504
 
                ptr = text[skip];
505
 
        }
506
 
 
507
 
        last = i = 0;
508
 
        while (1) {
509
 
                j = *ptr++;
510
 
                if ((j == '-' || j == ':') && !last) {
511
 
                        last++;
512
 
                        pattern->val.range.min = i;
513
 
                        i = 0;
514
 
                        continue;
515
 
                }
516
 
                j -= '0';
517
 
                if (j > 9)
518
 
                        // also catches the terminating zero
519
 
                        break;
520
 
                i *= 10;
521
 
                i += j;
522
 
        }
523
 
 
524
 
        if (last && *opaque >= 1 && *opaque <= 4)
525
 
                /* having a range with a min or a max is absurd */
526
 
                return 0;
527
 
 
528
 
        if (!last)
529
 
                pattern->val.range.min = i;
530
 
        pattern->val.range.max = i;
531
 
 
532
 
        switch (*opaque) {
533
 
        case 0: /* eq */
534
 
                pattern->val.range.min_set = 1;
535
 
                pattern->val.range.max_set = 1;
536
 
                break;
537
 
        case 1: /* gt */
538
 
                pattern->val.range.min++; /* gt = ge + 1 */
539
 
        case 2: /* ge */
540
 
                pattern->val.range.min_set = 1;
541
 
                pattern->val.range.max_set = 0;
542
 
                break;
543
 
        case 3: /* lt */
544
 
                pattern->val.range.max--; /* lt = le - 1 */
545
 
        case 4: /* le */
546
 
                pattern->val.range.min_set = 0;
547
 
                pattern->val.range.max_set = 1;
548
 
                break;
549
 
        }
550
 
        return skip + 1;
551
 
}
552
 
 
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
556
 
 * integer.
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
559
 
 * of 5 :
560
 
 *
561
 
 *    0:eq, 1:gt, 2:ge, 3:lt, 4:le
562
 
 *
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 :
567
 
 *
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
571
 
 *
572
 
 */
573
 
int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, int *opaque)
574
 
{
575
 
        signed long long i;
576
 
        unsigned int j, last, skip = 0;
577
 
        const char *ptr = *text;
578
 
 
579
 
 
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;
586
 
                else
587
 
                        return 0;
588
 
 
589
 
                skip++;
590
 
                ptr = text[skip];
591
 
        }
592
 
 
593
 
        last = i = 0;
594
 
        while (1) {
595
 
                j = *ptr++;
596
 
                if (j == '.') {
597
 
                        /* minor part */
598
 
                        if (i >= 65536)
599
 
                                return 0;
600
 
                        i <<= 16;
601
 
                        continue;
602
 
                }
603
 
                if ((j == '-' || j == ':') && !last) {
604
 
                        last++;
605
 
                        if (i < 65536)
606
 
                                i <<= 16;
607
 
                        pattern->val.range.min = i;
608
 
                        i = 0;
609
 
                        continue;
610
 
                }
611
 
                j -= '0';
612
 
                if (j > 9)
613
 
                        // also catches the terminating zero
614
 
                        break;
615
 
                i = (i & 0xFFFF0000) + (i & 0xFFFF) * 10;
616
 
                i += j;
617
 
        }
618
 
 
619
 
        /* if we only got a major version, let's shift it now */
620
 
        if (i < 65536)
621
 
                i <<= 16;
622
 
 
623
 
        if (last && *opaque >= 1 && *opaque <= 4)
624
 
                /* having a range with a min or a max is absurd */
625
 
                return 0;
626
 
 
627
 
        if (!last)
628
 
                pattern->val.range.min = i;
629
 
        pattern->val.range.max = i;
630
 
 
631
 
        switch (*opaque) {
632
 
        case 0: /* eq */
633
 
                pattern->val.range.min_set = 1;
634
 
                pattern->val.range.max_set = 1;
635
 
                break;
636
 
        case 1: /* gt */
637
 
                pattern->val.range.min++; /* gt = ge + 1 */
638
 
        case 2: /* ge */
639
 
                pattern->val.range.min_set = 1;
640
 
                pattern->val.range.max_set = 0;
641
 
                break;
642
 
        case 3: /* lt */
643
 
                pattern->val.range.max--; /* lt = le - 1 */
644
 
        case 4: /* le */
645
 
                pattern->val.range.min_set = 0;
646
 
                pattern->val.range.max_set = 1;
647
 
                break;
648
 
        }
649
 
        return skip + 1;
650
 
}
651
 
 
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,
655
 
 * otherwise 0.
656
 
 */
657
 
int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque)
658
 
{
659
 
        struct eb_root *tree = NULL;
660
 
        if (pattern->flags & ACL_PAT_F_TREE_OK)
661
 
                tree = pattern->val.tree;
662
 
 
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.
670
 
                 */
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 */
675
 
                        if (!node)
676
 
                                return 0;
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;
682
 
                        return 1;
683
 
                }
684
 
                return 1;
685
 
        }
686
 
        else
687
 
                return 0;
 
41
/* input values are 0 or 3, output is the same */
 
42
static inline enum acl_test_res pat2acl(struct pattern *pat)
 
43
{
 
44
        if (pat)
 
45
                return ACL_TEST_PASS;
 
46
        else
 
47
                return ACL_TEST_FAIL;
688
48
}
689
49
 
690
50
/*
719
79
}
720
80
 
721
81
/* Return a pointer to the ACL keyword <kw>, or NULL if not found. Note that if
722
 
 * <kw> contains an opening parenthesis, only the left part of it is checked.
 
82
 * <kw> contains an opening parenthesis or a comma, only the left part of it is
 
83
 * checked.
723
84
 */
724
85
struct acl_keyword *find_acl_kw(const char *kw)
725
86
{
727
88
        const char *kwend;
728
89
        struct acl_kw_list *kwl;
729
90
 
730
 
        kwend = strchr(kw, '(');
731
 
        if (!kwend)
732
 
                kwend = kw + strlen(kw);
 
91
        kwend = kw;
 
92
        while (*kwend && *kwend != '(' && *kwend != ',')
 
93
                kwend++;
733
94
 
734
95
        list_for_each_entry(kwl, &acl_keywords.list, list) {
735
96
                for (index = 0; kwl->kw[index].kw != NULL; index++) {
741
102
        return NULL;
742
103
}
743
104
 
744
 
/* NB: does nothing if <pat> is NULL */
745
 
static void free_pattern(struct acl_pattern *pat)
746
 
{
747
 
        if (!pat)
748
 
                return;
749
 
 
750
 
        if (pat->ptr.ptr) {
751
 
                if (pat->freeptrbuf)
752
 
                        pat->freeptrbuf(pat->ptr.ptr);
753
 
 
754
 
                free(pat->ptr.ptr);
755
 
        }
756
 
 
757
 
        free(pat);
758
 
}
759
 
 
760
 
static void free_pattern_list(struct list *head)
761
 
{
762
 
        struct acl_pattern *pat, *tmp;
763
 
        list_for_each_entry_safe(pat, tmp, head, list)
764
 
                free_pattern(pat);
765
 
}
766
 
 
767
 
static void free_pattern_tree(struct eb_root *root)
768
 
{
769
 
        struct eb_node *node, *next;
770
 
        node = eb_first(root);
771
 
        while (node) {
772
 
                next = eb_next(node);
773
 
                eb_delete(node);
774
 
                free(node);
775
 
                node = next;
776
 
        }
777
 
}
778
 
 
779
105
static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
780
106
{
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)
785
 
                free(expr->arg.str);
786
 
        expr->kw->use_cnt--;
 
107
        struct arg *arg;
 
108
 
 
109
        pattern_prune(&expr->pat);
 
110
 
 
111
        for (arg = expr->smp->arg_p; arg; arg++) {
 
112
                if (arg->type == ARGT_STOP)
 
113
                        break;
 
114
                if (arg->type == ARGT_STR || arg->unresolved) {
 
115
                        free(arg->data.str.str);
 
116
                        arg->data.str.str = NULL;
 
117
                        arg->unresolved = 0;
 
118
                }
 
119
        }
 
120
 
 
121
        if (expr->smp->arg_p != empty_arg_list)
 
122
                free(expr->smp->arg_p);
787
123
        return expr;
788
124
}
789
125
 
790
 
static int acl_read_patterns_from_file( struct acl_keyword *aclkw,
791
 
                                        struct acl_expr *expr,
792
 
                                        const char *filename, int patflags)
793
 
{
794
 
        FILE *file;
795
 
        char *c;
796
 
        const char *args[2];
797
 
        struct acl_pattern *pattern;
798
 
        int opaque;
799
 
        int ret = 0;
800
 
 
801
 
        file = fopen(filename, "r");
802
 
        if (!file)
803
 
                return 0;
804
 
 
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.
808
 
         */
809
 
        opaque = 0;
810
 
        pattern = NULL;
811
 
        args[1] = "";
812
 
        while (fgets(trash, trashlen, file) != NULL) {
813
 
                c = trash;
814
 
 
815
 
                /* ignore lines beginning with a dash */
816
 
                if (*c == '#')
817
 
                        continue;
818
 
 
819
 
                /* strip leading spaces and tabs */
820
 
                while (*c == ' ' || *c == '\t')
821
 
                        c++;
822
 
 
823
 
 
824
 
                args[0] = c;
825
 
                while (*c && *c != '\n' && *c != '\r')
826
 
                        c++;
827
 
                *c = 0;
828
 
 
829
 
                /* empty lines are ignored too */
830
 
                if (c == args[0])
831
 
                        continue;
832
 
 
833
 
                /* we keep the previous pattern along iterations as long as it's not used */
834
 
                if (!pattern)
835
 
                        pattern = (struct acl_pattern *)malloc(sizeof(*pattern));
836
 
                if (!pattern)
837
 
                        goto out_close;
838
 
 
839
 
                memset(pattern, 0, sizeof(*pattern));
840
 
                pattern->flags = patflags;
841
 
 
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.
845
 
                         */
846
 
                        pattern->flags |= ACL_PAT_F_TREE_OK;
847
 
                        pattern->val.tree = &expr->pattern_tree;
848
 
                }
849
 
 
850
 
                if (!aclkw->parse(args, pattern, &opaque))
851
 
                        goto out_free_pattern;
852
 
 
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 */
857
 
                }
858
 
        }
859
 
 
860
 
        ret = 1; /* success */
861
 
 
862
 
 out_free_pattern:
863
 
        free_pattern(pattern);
864
 
 out_close:
865
 
        fclose(file);
866
 
        return ret;
867
 
}
868
 
 
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.
 
130
 *
870
131
 * Right now, the only accepted syntax is :
871
132
 * <subject> [<value>...]
872
133
 */
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)
874
136
{
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;
 
140
        int patflags;
880
141
        const char *arg;
 
142
        struct sample_expr *smp = NULL;
 
143
        int idx = 0;
 
144
        char *ckw = NULL;
 
145
        const char *begw;
 
146
        const char *endw;
 
147
        const char *endt;
 
148
        unsigned long prev_type;
 
149
        int cur_type;
 
150
        int nbargs;
 
151
        int operator = STD_OP_EQ;
 
152
        int op;
 
153
        int contain_colon, have_dot;
 
154
        const char *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];
 
158
        int is_loaded;
 
159
        int unique_id;
 
160
        char *error;
 
161
        struct pat_ref *ref;
 
162
        struct pattern_expr *pattern_expr;
 
163
        int load_as_map = 0;
 
164
 
 
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
 
167
         * keyword.
 
168
         */
 
169
 
 
170
        al->ctx  = ARGC_ACL;   // to report errors while resolving args late
 
171
        al->kw   = *args;
 
172
        al->conv = NULL;
881
173
 
882
174
        aclkw = find_acl_kw(args[0]);
883
 
        if (!aclkw || !aclkw->parse)
884
 
                goto out_return;
 
175
        if (aclkw) {
 
176
                /* OK we have a real ACL keyword */
 
177
 
 
178
                /* build new sample expression for this ACL */
 
179
                smp = calloc(1, sizeof(struct sample_expr));
 
180
                if (!smp) {
 
181
                        memprintf(err, "out of memory when parsing ACL expression");
 
182
                        goto out_return;
 
183
                }
 
184
                LIST_INIT(&(smp->conv_exprs));
 
185
                smp->fetch = aclkw->smp;
 
186
                smp->arg_p = empty_arg_list;
 
187
 
 
188
                /* look for the begining of the subject arguments */
 
189
                for (arg = args[0]; *arg && *arg != '(' && *arg != ','; arg++);
 
190
 
 
191
                endt = arg;
 
192
                if (*endt == '(') {
 
193
                        /* look for the end of this term and skip the opening parenthesis */
 
194
                        endt = ++arg;
 
195
                        while (*endt && *endt != ')')
 
196
                                endt++;
 
197
                        if (*endt != ')') {
 
198
                                memprintf(err, "missing closing ')' after arguments to ACL keyword '%s'", aclkw->kw);
 
199
                                goto out_free_smp;
 
200
                        }
 
201
                }
 
202
 
 
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
 
207
                 *               if present).
 
208
                 *   - endt    : end of the term (=arg or last parenthesis if args are present)
 
209
                 */
 
210
                nbargs = make_arg_list(arg, endt - arg, smp->fetch->arg_mask, &smp->arg_p,
 
211
                                       err, NULL, NULL, al);
 
212
                if (nbargs < 0) {
 
213
                        /* note that make_arg_list will have set <err> here */
 
214
                        memprintf(err, "ACL keyword '%s' : %s", aclkw->kw, *err);
 
215
                        goto out_free_smp;
 
216
                }
 
217
 
 
218
                if (!smp->arg_p) {
 
219
                        smp->arg_p = empty_arg_list;
 
220
                }
 
221
                else if (smp->fetch->val_args && !smp->fetch->val_args(smp->arg_p, err)) {
 
222
                        /* invalid keyword argument, error must have been
 
223
                         * set by val_args().
 
224
                         */
 
225
                        memprintf(err, "in argument to '%s', %s", aclkw->kw, *err);
 
226
                        goto out_free_smp;
 
227
                }
 
228
                arg = endt;
 
229
 
 
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.
 
232
                 */
 
233
                prev_type = smp->fetch->out_type;
 
234
                while (*arg) {
 
235
                        struct sample_conv *conv;
 
236
                        struct sample_conv_expr *conv_expr;
 
237
 
 
238
                        if (*arg == ')') /* skip last closing parenthesis */
 
239
                                arg++;
 
240
 
 
241
                        if (*arg && *arg != ',') {
 
242
                                if (ckw)
 
243
                                        memprintf(err, "ACL keyword '%s' : missing comma after conv keyword '%s'.",
 
244
                                                  aclkw->kw, ckw);
 
245
                                else
 
246
                                        memprintf(err, "ACL keyword '%s' : missing comma after fetch keyword.",
 
247
                                                  aclkw->kw);
 
248
                                goto out_free_smp;
 
249
                        }
 
250
 
 
251
                        while (*arg == ',') /* then trailing commas */
 
252
                                arg++;
 
253
 
 
254
                        begw = arg; /* start of conv keyword */
 
255
 
 
256
                        if (!*begw)
 
257
                                /* none ? end of converters */
 
258
                                break;
 
259
 
 
260
                        for (endw = begw; *endw && *endw != '(' && *endw != ','; endw++);
 
261
 
 
262
                        free(ckw);
 
263
                        ckw = my_strndup(begw, endw - begw);
 
264
 
 
265
                        conv = find_sample_conv(begw, endw - begw);
 
266
                        if (!conv) {
 
267
                                /* Unknown converter method */
 
268
                                memprintf(err, "ACL keyword '%s' : unknown conv method '%s'.",
 
269
                                          aclkw->kw, ckw);
 
270
                                goto out_free_smp;
 
271
                        }
 
272
 
 
273
                        arg = endw;
 
274
                        if (*arg == '(') {
 
275
                                /* look for the end of this term */
 
276
                                while (*arg && *arg != ')')
 
277
                                        arg++;
 
278
                                if (*arg != ')') {
 
279
                                        memprintf(err, "ACL keyword '%s' : syntax error: missing ')' after conv keyword '%s'.",
 
280
                                                  aclkw->kw, ckw);
 
281
                                        goto out_free_smp;
 
282
                                }
 
283
                        }
 
284
 
 
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.",
 
287
                                          aclkw->kw, ckw);
 
288
                                goto out_free_smp;
 
289
                        }
 
290
 
 
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.",
 
294
                                          aclkw->kw, ckw);
 
295
                                goto out_free_smp;
 
296
                        }
 
297
 
 
298
                        prev_type = conv->out_type;
 
299
                        conv_expr = calloc(1, sizeof(struct sample_conv_expr));
 
300
                        if (!conv_expr)
 
301
                                goto out_free_smp;
 
302
 
 
303
                        LIST_ADDQ(&(smp->conv_exprs), &(conv_expr->list));
 
304
                        conv_expr->conv = conv;
 
305
 
 
306
                        if (arg != endw) {
 
307
                                int err_arg;
 
308
 
 
309
                                if (!conv->arg_mask) {
 
310
                                        memprintf(err, "ACL keyword '%s' : conv method '%s' does not support any args.",
 
311
                                                  aclkw->kw, ckw);
 
312
                                        goto out_free_smp;
 
313
                                }
 
314
 
 
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);
 
320
                                        goto out_free_smp;
 
321
                                }
 
322
 
 
323
                                if (!conv_expr->arg_p)
 
324
                                        conv_expr->arg_p = empty_arg_list;
 
325
 
 
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);
 
329
                                        goto out_free_smp;
 
330
                                }
 
331
                        }
 
332
                        else if (ARGM(conv->arg_mask)) {
 
333
                                memprintf(err, "ACL keyword '%s' : missing args for conv method '%s'.",
 
334
                                          aclkw->kw, ckw);
 
335
                                goto out_free_smp;
 
336
                        }
 
337
                }
 
338
        }
 
339
        else {
 
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.
 
344
                 */
 
345
                smp = sample_parse_expr((char **)args, &idx, file, line, err, al);
 
346
                if (!smp) {
 
347
                        memprintf(err, "%s in ACL expression '%s'", *err, *args);
 
348
                        goto out_return;
 
349
                }
 
350
        }
885
351
 
886
352
        expr = (struct acl_expr *)calloc(1, sizeof(*expr));
887
 
        if (!expr)
 
353
        if (!expr) {
 
354
                memprintf(err, "out of memory when parsing ACL expression");
888
355
                goto out_return;
889
 
 
890
 
        expr->kw = aclkw;
891
 
        aclkw->use_cnt++;
892
 
        LIST_INIT(&expr->patterns);
893
 
        expr->pattern_tree = EB_ROOT_UNIQUE;
894
 
        expr->arg.str = NULL;
895
 
        expr->arg_len = 0;
896
 
 
897
 
        arg = strchr(args[0], '(');
898
 
        if (arg != NULL) {
899
 
                char *end, *arg2;
900
 
                /* there is an argument in the form "subject(arg)" */
901
 
                arg++;
902
 
                end = strchr(arg, ')');
903
 
                if (!end)
904
 
                        goto out_free_expr;
905
 
                arg2 = my_strndup(arg, end - arg);
906
 
                if (!arg2)
907
 
                        goto out_free_expr;
908
 
                expr->arg_len = end - arg;
909
 
                expr->arg.str = arg2;
 
356
        }
 
357
 
 
358
        pattern_init_head(&expr->pat);
 
359
 
 
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;
 
367
        expr->smp = smp;
 
368
        smp = NULL;
 
369
 
 
370
        /* Fill NULL pointers with values provided by the pattern.c arrays */
 
371
        if (aclkw) {
 
372
                if (!expr->pat.parse)
 
373
                        expr->pat.parse = pat_parse_fcts[aclkw->match_type];
 
374
 
 
375
                if (!expr->pat.index)
 
376
                        expr->pat.index = pat_index_fcts[aclkw->match_type];
 
377
 
 
378
                if (!expr->pat.match)
 
379
                        expr->pat.match = pat_match_fcts[aclkw->match_type];
 
380
 
 
381
                if (!expr->pat.delete)
 
382
                        expr->pat.delete = pat_delete_fcts[aclkw->match_type];
 
383
 
 
384
                if (!expr->pat.prune)
 
385
                        expr->pat.prune = pat_prune_fcts[aclkw->match_type];
 
386
        }
 
387
 
 
388
        if (!expr->pat.parse) {
 
389
                /* some types can be automatically converted */
 
390
 
 
391
                switch (expr->smp ? expr->smp->fetch->out_type : aclkw->smp->out_type) {
 
392
                case SMP_T_BOOL:
 
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];
 
399
                        break;
 
400
                case SMP_T_SINT:
 
401
                case SMP_T_UINT:
 
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];
 
408
                        break;
 
409
                case SMP_T_IPV4:
 
410
                case SMP_T_IPV6:
 
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];
 
417
                        break;
 
418
                case SMP_T_STR:
 
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];
 
425
                        break;
 
426
                }
 
427
        }
 
428
 
 
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"
 
437
                        "\n",
 
438
                        args[0]);
910
439
        }
911
440
 
912
441
        args++;
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
918
450
         */
919
451
        patflags = 0;
 
452
        is_loaded = 0;
 
453
        unique_id = -1;
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))
925
 
                                goto out_free_expr;
926
 
                        args++;
927
 
                }
928
 
                else if ((*args)[1] == '-') {
929
 
                        args++;
930
 
                        break;
931
 
                }
932
 
                else
933
 
                        break;
 
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");
 
463
                                goto out_free_expr;
 
464
                        }
 
465
 
 
466
                        /* Check if this id is really unique. */
 
467
                        if (pat_ref_lookupid(unique_id)) {
 
468
                                memprintf(err, "the id is already used");
 
469
                                goto out_free_expr;
 
470
                        }
 
471
 
 
472
                        args++;
 
473
                }
 
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);
 
477
                                goto out_free_expr;
 
478
                        }
 
479
 
 
480
                        if (!pattern_read_from_file(&expr->pat, PAT_REF_ACL, args[1], patflags, load_as_map, err, file, line))
 
481
                                goto out_free_expr;
 
482
                        is_loaded = 1;
 
483
                        args++;
 
484
                }
 
485
                else if (strcmp(*args, "-m") == 0) {
 
486
                        int idx;
 
487
 
 
488
                        if (is_loaded) {
 
489
                                memprintf(err, "'-m' must only be specified before patterns and files in parsing ACL expression");
 
490
                                goto out_free_expr;
 
491
                        }
 
492
 
 
493
                        idx = pat_find_match_name(args[1]);
 
494
                        if (idx < 0) {
 
495
                                memprintf(err, "unknown matching method '%s' when parsing ACL expression", args[1]);
 
496
                                goto out_free_expr;
 
497
                        }
 
498
 
 
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);
 
502
                                goto out_free_expr;
 
503
                        }
 
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];
 
510
                        args++;
 
511
                }
 
512
                else if (strcmp(*args, "-M") == 0) {
 
513
                        load_as_map = 1;
 
514
                }
 
515
                else if (strcmp(*args, "--") == 0) {
 
516
                        args++;
 
517
                        break;
 
518
                }
 
519
                else {
 
520
                        memprintf(err, "'%s' is not a valid ACL option. Please use '--' before any pattern beginning with a '-'", args[0]);
 
521
                        goto out_free_expr;
 
522
                        break;
 
523
                }
934
524
                args++;
935
525
        }
936
526
 
 
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);
 
529
                goto out_free_expr;
 
530
        }
 
531
 
 
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';
 
535
 
 
536
        /* Create new patern reference. */
 
537
        ref = pat_ref_newid(unique_id, trash.str, PAT_REF_ACL);
 
538
        if (!ref) {
 
539
                memprintf(err, "memory error");
 
540
                goto out_free_expr;
 
541
        }
 
542
 
 
543
        /* Create new pattern expression associated to this reference. */
 
544
        pattern_expr = pattern_new_expr(&expr->pat, ref, err);
 
545
        if (!pattern_expr)
 
546
                goto out_free_expr;
 
547
 
 
548
        /* Copy the pattern matching and indexing flags. */
 
549
        pattern_expr->mflags = patflags;
 
550
 
937
551
        /* now parse all patterns */
938
 
        opaque = 0;
939
552
        while (**args) {
940
 
                int ret;
941
 
                pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
942
 
                if (!pattern)
 
553
                arg = *args;
 
554
 
 
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:
 
560
                 *
 
561
                 * pat_parse_int():
 
562
                 *
 
563
                 *   "eq x" -> "x" or "x:x"
 
564
                 *   "le x" -> ":x"
 
565
                 *   "lt x" -> ":y" (with y = x - 1)
 
566
                 *   "ge x" -> "x:"
 
567
                 *   "gt x" -> "y:" (with y = x + 1)
 
568
                 *
 
569
                 * pat_parse_dotted_ver():
 
570
                 *
 
571
                 *   "eq x.y" -> "x.y" or "x.y:x.y"
 
572
                 *   "le x.y" -> ":x.y"
 
573
                 *   "lt x.y" -> ":w.z" (with w.z = x.y - 1)
 
574
                 *   "ge x.y" -> "x.y:"
 
575
                 *   "gt x.y" -> "w.z:" (with w.z = x.y + 1)
 
576
                 *
 
577
                 * If y is not present, assume that is "0".
 
578
                 *
 
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.
 
582
                 */
 
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.
 
587
                         */
 
588
                        op = get_std_op(arg);
 
589
                        if (op != -1) {
 
590
                                operator = op;
 
591
                                args++;
 
592
                                continue;
 
593
                        }
 
594
 
 
595
                        /* Check if the pattern contain ':' or '-' character. */
 
596
                        contain_colon = (strchr(arg, ':') || strchr(arg, '-'));
 
597
 
 
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.
 
601
                         */
 
602
                        if (!contain_colon && operator != STD_OP_EQ) {
 
603
                                /* Search '.' separator. */
 
604
                                dot = strchr(arg, '.');
 
605
                                if (!dot) {
 
606
                                        have_dot = 0;
 
607
                                        minor = 0;
 
608
                                        dot = arg + strlen(arg);
 
609
                                }
 
610
                                else
 
611
                                        have_dot = 1;
 
612
 
 
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);
 
617
                                                goto out_free_expr;
 
618
                                        }
 
619
                                        if (minor >= 65536) {
 
620
                                                memprintf(err, "'%s' contains too large a minor value", arg);
 
621
                                                goto out_free_expr;
 
622
                                        }
 
623
                                }
 
624
 
 
625
                                /* convert the integer value for the pat_parse_int() function, and the
 
626
                                 * integer major part for the pat_parse_dotted_ver() function.
 
627
                                 */
 
628
                                if (strl2llrc(arg, dot - arg, &value) != 0) {
 
629
                                        memprintf(err, "'%s' is neither a number nor a supported operator", arg);
 
630
                                        goto out_free_expr;
 
631
                                }
 
632
                                if (expr->pat.parse == pat_parse_dotted_ver)  {
 
633
                                        if (value >= 65536) {
 
634
                                                memprintf(err, "'%s' contains too large a major value", arg);
 
635
                                                goto out_free_expr;
 
636
                                        }
 
637
                                        value = (value << 16) | (minor & 0xffff);
 
638
                                }
 
639
 
 
640
                                switch (operator) {
 
641
 
 
642
                                case STD_OP_EQ: /* this case is not possible. */
 
643
                                        memprintf(err, "internal error");
 
644
                                        goto out_free_expr;
 
645
 
 
646
                                case STD_OP_GT:
 
647
                                        value++; /* gt = ge + 1 */
 
648
 
 
649
                                case STD_OP_GE:
 
650
                                        if (expr->pat.parse == pat_parse_int)
 
651
                                                snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, "%lld:", value);
 
652
                                        else
 
653
                                                snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, "%lld.%lld:",
 
654
                                                         value >> 16, value & 0xffff);
 
655
                                        arg = buffer;
 
656
                                        break;
 
657
 
 
658
                                case STD_OP_LT:
 
659
                                        value--; /* lt = le - 1 */
 
660
 
 
661
                                case STD_OP_LE:
 
662
                                        if (expr->pat.parse == pat_parse_int)
 
663
                                                snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, ":%lld", value);
 
664
                                        else
 
665
                                                snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, ":%lld.%lld",
 
666
                                                         value >> 16, value & 0xffff);
 
667
                                        arg = buffer;
 
668
                                        break;
 
669
                                }
 
670
                        }
 
671
                }
 
672
 
 
673
                /* Add sample to the reference, and try to compile it fior each pattern
 
674
                 * using this value.
 
675
                 */
 
676
                if (!pat_ref_add(ref, arg, NULL, err))
943
677
                        goto out_free_expr;
944
 
                pattern->flags = patflags;
945
 
 
946
 
                ret = aclkw->parse(args, pattern, &opaque);
947
 
                if (!ret)
948
 
                        goto out_free_pattern;
949
 
                LIST_ADDQ(&expr->patterns, &pattern->list);
950
 
                args += ret;
 
678
                args++;
951
679
        }
952
680
 
953
681
        return expr;
954
682
 
955
 
 out_free_pattern:
956
 
        free_pattern(pattern);
957
683
 out_free_expr:
958
684
        prune_acl_expr(expr);
959
685
        free(expr);
 
686
        free(ckw);
 
687
 out_free_smp:
 
688
        free(smp);
960
689
 out_return:
961
690
        return NULL;
962
691
}
980
709
/* Parse an ACL with the name starting at <args>[0], and with a list of already
981
710
 * known ACLs in <acl>. If the ACL was not in the list, it will be added.
982
711
 * A pointer to that ACL is returned. If the ACL has an empty name, then it's
983
 
 * an anonymous one and it won't be merged with any other one.
 
712
 * an anonymous one and it won't be merged with any other one. If <err> is not
 
713
 * NULL, it will be filled with an appropriate error. This pointer must be
 
714
 * freeable or NULL. <al> is the arg_list serving as a head for unresolved
 
715
 * dependencies.
984
716
 *
985
717
 * args syntax: <aclname> <acl_expr>
986
718
 */
987
 
struct acl *parse_acl(const char **args, struct list *known_acl)
 
719
struct acl *parse_acl(const char **args, struct list *known_acl, char **err, struct arg_list *al,
 
720
                      const char *file, int line)
988
721
{
989
722
        __label__ out_return, out_free_acl_expr, out_free_name;
990
723
        struct acl *cur_acl;
991
724
        struct acl_expr *acl_expr;
992
725
        char *name;
993
 
 
994
 
        if (**args && invalid_char(*args))
995
 
                goto out_return;
996
 
 
997
 
        acl_expr = parse_acl_expr(args + 1);
998
 
        if (!acl_expr)
999
 
                goto out_return;
 
726
        const char *pos;
 
727
 
 
728
        if (**args && (pos = invalid_char(*args))) {
 
729
                memprintf(err, "invalid character in ACL name : '%c'", *pos);
 
730
                goto out_return;
 
731
        }
 
732
 
 
733
        acl_expr = parse_acl_expr(args + 1, err, al, file, line);
 
734
        if (!acl_expr) {
 
735
                /* parse_acl_expr will have filled <err> here */
 
736
                goto out_return;
 
737
        }
1000
738
 
1001
739
        /* Check for args beginning with an opening parenthesis just after the
1002
740
         * subject, as this is almost certainly a typo. Right now we can only
1017
755
 
1018
756
        if (!cur_acl) {
1019
757
                name = strdup(args[0]);
1020
 
                if (!name)
 
758
                if (!name) {
 
759
                        memprintf(err, "out of memory when parsing ACL");
1021
760
                        goto out_free_acl_expr;
 
761
                }
1022
762
                cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
1023
 
                if (cur_acl == NULL)
 
763
                if (cur_acl == NULL) {
 
764
                        memprintf(err, "out of memory when parsing ACL");
1024
765
                        goto out_free_name;
 
766
                }
1025
767
 
1026
768
                LIST_INIT(&cur_acl->expr);
1027
769
                LIST_ADDQ(known_acl, &cur_acl->list);
1028
770
                cur_acl->name = name;
1029
771
        }
1030
772
 
1031
 
        cur_acl->requires |= acl_expr->kw->requires;
 
773
        /* We want to know what features the ACL needs (typically HTTP parsing),
 
774
         * and where it may be used. If an ACL relies on multiple matches, it is
 
775
         * OK if at least one of them may match in the context where it is used.
 
776
         */
 
777
        cur_acl->use |= acl_expr->smp->fetch->use;
 
778
        cur_acl->val |= acl_expr->smp->fetch->val;
1032
779
        LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
1033
780
        return cur_acl;
1034
781
 
1072
819
/* Find a default ACL from the default_acl list, compile it and return it.
1073
820
 * If the ACL is not found, NULL is returned. In theory, it cannot fail,
1074
821
 * except when default ACLs are broken, in which case it will return NULL.
1075
 
 * If <known_acl> is not NULL, the ACL will be queued at its tail.
 
822
 * If <known_acl> is not NULL, the ACL will be queued at its tail. If <err> is
 
823
 * not NULL, it will be filled with an error message if an error occurs. This
 
824
 * pointer must be freeable or NULL. <al> is an arg_list serving as a list head
 
825
 * to report missing dependencies.
1076
826
 */
1077
 
struct acl *find_acl_default(const char *acl_name, struct list *known_acl)
 
827
static struct acl *find_acl_default(const char *acl_name, struct list *known_acl,
 
828
                                    char **err, struct arg_list *al,
 
829
                                    const char *file, int line)
1078
830
{
1079
831
        __label__ out_return, out_free_acl_expr, out_free_name;
1080
832
        struct acl *cur_acl;
1087
839
                        break;
1088
840
        }
1089
841
 
1090
 
        if (default_acl_list[index].name == NULL)
 
842
        if (default_acl_list[index].name == NULL) {
 
843
                memprintf(err, "no such ACL : '%s'", acl_name);
1091
844
                return NULL;
 
845
        }
1092
846
 
1093
 
        acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr);
1094
 
        if (!acl_expr)
 
847
        acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr, err, al, file, line);
 
848
        if (!acl_expr) {
 
849
                /* parse_acl_expr must have filled err here */
1095
850
                goto out_return;
 
851
        }
1096
852
 
1097
853
        name = strdup(acl_name);
1098
 
        if (!name)
 
854
        if (!name) {
 
855
                memprintf(err, "out of memory when building default ACL '%s'", acl_name);
1099
856
                goto out_free_acl_expr;
 
857
        }
 
858
 
1100
859
        cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
1101
 
        if (cur_acl == NULL)
 
860
        if (cur_acl == NULL) {
 
861
                memprintf(err, "out of memory when building default ACL '%s'", acl_name);
1102
862
                goto out_free_name;
 
863
        }
1103
864
 
1104
865
        cur_acl->name = name;
1105
 
        cur_acl->requires |= acl_expr->kw->requires;
 
866
        cur_acl->use |= acl_expr->smp->fetch->use;
 
867
        cur_acl->val |= acl_expr->smp->fetch->val;
1106
868
        LIST_INIT(&cur_acl->expr);
1107
869
        LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
1108
870
        if (known_acl)
1136
898
 
1137
899
/* Parse an ACL condition starting at <args>[0], relying on a list of already
1138
900
 * known ACLs passed in <known_acl>. The new condition is returned (or NULL in
1139
 
 * case of low memory). Supports multiple conditions separated by "or".
 
901
 * case of low memory). Supports multiple conditions separated by "or". If
 
902
 * <err> is not NULL, it will be filled with a pointer to an error message in
 
903
 * case of error, that the caller is responsible for freeing. The initial
 
904
 * location must either be freeable or NULL. The list <al> serves as a list head
 
905
 * for unresolved dependencies.
1140
906
 */
1141
 
struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol)
 
907
struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl,
 
908
                                enum acl_cond_pol pol, char **err, struct arg_list *al,
 
909
                                const char *file, int line)
1142
910
{
1143
911
        __label__ out_return, out_free_suite, out_free_term;
1144
912
        int arg, neg;
1147
915
        struct acl_term *cur_term;
1148
916
        struct acl_term_suite *cur_suite;
1149
917
        struct acl_cond *cond;
 
918
        unsigned int suite_val;
1150
919
 
1151
920
        cond = (struct acl_cond *)calloc(1, sizeof(*cond));
1152
 
        if (cond == NULL)
 
921
        if (cond == NULL) {
 
922
                memprintf(err, "out of memory when parsing condition");
1153
923
                goto out_return;
 
924
        }
1154
925
 
1155
926
        LIST_INIT(&cond->list);
1156
927
        LIST_INIT(&cond->suites);
1157
928
        cond->pol = pol;
 
929
        cond->val = 0;
1158
930
 
1159
931
        cur_suite = NULL;
 
932
        suite_val = ~0U;
1160
933
        neg = 0;
1161
934
        for (arg = 0; *args[arg]; arg++) {
1162
935
                word = args[arg];
1175
948
 
1176
949
                if (strcasecmp(word, "or") == 0 || strcmp(word, "||") == 0) {
1177
950
                        /* new term suite */
 
951
                        cond->val |= suite_val;
 
952
                        suite_val = ~0U;
1178
953
                        cur_suite = NULL;
1179
954
                        neg = 0;
1180
955
                        continue;
1190
965
                        while (*args[arg_end] && strcmp(args[arg_end], "}") != 0)
1191
966
                                arg_end++;
1192
967
 
1193
 
                        if (!*args[arg_end])
 
968
                        if (!*args[arg_end]) {
 
969
                                memprintf(err, "missing closing '}' in condition");
1194
970
                                goto out_free_suite;
 
971
                        }
1195
972
 
1196
973
                        args_new = calloc(1, (arg_end - arg + 1) * sizeof(*args_new));
1197
 
                        if (!args_new)
 
974
                        if (!args_new) {
 
975
                                memprintf(err, "out of memory when parsing condition");
1198
976
                                goto out_free_suite;
 
977
                        }
1199
978
 
1200
979
                        args_new[0] = "";
1201
980
                        memcpy(args_new + 1, args + arg + 1, (arg_end - arg) * sizeof(*args_new));
1202
981
                        args_new[arg_end - arg] = "";
1203
 
                        cur_acl = parse_acl(args_new, known_acl);
 
982
                        cur_acl = parse_acl(args_new, known_acl, err, al, file, line);
1204
983
                        free(args_new);
1205
984
 
1206
 
                        if (!cur_acl)
 
985
                        if (!cur_acl) {
 
986
                                /* note that parse_acl() must have filled <err> here */
1207
987
                                goto out_free_suite;
 
988
                        }
 
989
                        word = args[arg + 1];
1208
990
                        arg = arg_end;
1209
991
                }
1210
992
                else {
1215
997
                         */
1216
998
                        cur_acl = find_acl_by_name(word, known_acl);
1217
999
                        if (cur_acl == NULL) {
1218
 
                                cur_acl = find_acl_default(word, known_acl);
1219
 
                                if (cur_acl == NULL)
 
1000
                                cur_acl = find_acl_default(word, known_acl, err, al, file, line);
 
1001
                                if (cur_acl == NULL) {
 
1002
                                        /* note that find_acl_default() must have filled <err> here */
1220
1003
                                        goto out_free_suite;
 
1004
                                }
1221
1005
                        }
1222
1006
                }
1223
1007
 
1224
1008
                cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term));
1225
 
                if (cur_term == NULL)
 
1009
                if (cur_term == NULL) {
 
1010
                        memprintf(err, "out of memory when parsing condition");
1226
1011
                        goto out_free_suite;
 
1012
                }
1227
1013
 
1228
1014
                cur_term->acl = cur_acl;
1229
1015
                cur_term->neg = neg;
1230
 
                cond->requires |= cur_acl->requires;
 
1016
 
 
1017
                /* Here it is a bit complex. The acl_term_suite is a conjunction
 
1018
                 * of many terms. It may only be used if all of its terms are
 
1019
                 * usable at the same time. So the suite's validity domain is an
 
1020
                 * AND between all ACL keywords' ones. But, the global condition
 
1021
                 * is valid if at least one term suite is OK. So it's an OR between
 
1022
                 * all of their validity domains. We could emit a warning as soon
 
1023
                 * as suite_val is null because it means that the last ACL is not
 
1024
                 * compatible with the previous ones. Let's remain simple for now.
 
1025
                 */
 
1026
                cond->use |= cur_acl->use;
 
1027
                suite_val &= cur_acl->val;
1231
1028
 
1232
1029
                if (!cur_suite) {
1233
1030
                        cur_suite = (struct acl_term_suite *)calloc(1, sizeof(*cur_suite));
1234
 
                        if (cur_suite == NULL)
 
1031
                        if (cur_suite == NULL) {
 
1032
                                memprintf(err, "out of memory when parsing condition");
1235
1033
                                goto out_free_term;
 
1034
                        }
1236
1035
                        LIST_INIT(&cur_suite->terms);
1237
1036
                        LIST_ADDQ(&cond->suites, &cur_suite->list);
1238
1037
                }
1240
1039
                neg = 0;
1241
1040
        }
1242
1041
 
 
1042
        cond->val |= suite_val;
1243
1043
        return cond;
1244
1044
 
1245
1045
 out_free_term:
1254
1054
/* Builds an ACL condition starting at the if/unless keyword. The complete
1255
1055
 * condition is returned. NULL is returned in case of error or if the first
1256
1056
 * word is neither "if" nor "unless". It automatically sets the file name and
1257
 
 * the line number in the condition for better error reporting, and adds the
1258
 
 * ACL requirements to the proxy's acl_requires.
 
1057
 * the line number in the condition for better error reporting, and sets the
 
1058
 * HTTP intiailization requirements in the proxy. If <err> is not NULL, it will
 
1059
 * be filled with a pointer to an error message in case of error, that the
 
1060
 * caller is responsible for freeing. The initial location must either be
 
1061
 * freeable or NULL.
1259
1062
 */
1260
 
struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args)
 
1063
struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args, char **err)
1261
1064
{
1262
 
        int pol = ACL_COND_NONE;
 
1065
        enum acl_cond_pol pol = ACL_COND_NONE;
1263
1066
        struct acl_cond *cond = NULL;
1264
1067
 
 
1068
        if (err)
 
1069
                *err = NULL;
 
1070
 
1265
1071
        if (!strcmp(*args, "if")) {
1266
1072
                pol = ACL_COND_IF;
1267
1073
                args++;
1270
1076
                pol = ACL_COND_UNLESS;
1271
1077
                args++;
1272
1078
        }
1273
 
        else
 
1079
        else {
 
1080
                memprintf(err, "conditions must start with either 'if' or 'unless'");
1274
1081
                return NULL;
 
1082
        }
1275
1083
 
1276
 
        cond = parse_acl_cond(args, &px->acl, pol);
1277
 
        if (!cond)
 
1084
        cond = parse_acl_cond(args, &px->acl, pol, err, &px->conf.args, file, line);
 
1085
        if (!cond) {
 
1086
                /* note that parse_acl_cond must have filled <err> here */
1278
1087
                return NULL;
 
1088
        }
1279
1089
 
1280
1090
        cond->file = file;
1281
1091
        cond->line = line;
1282
 
        px->acl_requires |= cond->requires;
1283
 
 
 
1092
        px->http_needed |= !!(cond->use & SMP_USE_HTTP_ANY);
1284
1093
        return cond;
1285
1094
}
1286
1095
 
1287
 
/* Execute condition <cond> and return either ACL_PAT_FAIL, ACL_PAT_MISS or
1288
 
 * ACL_PAT_PASS depending on the test results. ACL_PAT_MISS may only be
1289
 
 * returned if <dir> contains ACL_PARTIAL, indicating that incomplete data
1290
 
 * is being examined.
1291
 
 * This function only computes the condition, it does not apply the polarity
1292
 
 * required by IF/UNLESS, it's up to the caller to do this using something like
1293
 
 * this :
 
1096
/* Execute condition <cond> and return either ACL_TEST_FAIL, ACL_TEST_MISS or
 
1097
 * ACL_TEST_PASS depending on the test results. ACL_TEST_MISS may only be
 
1098
 * returned if <opt> does not contain SMP_OPT_FINAL, indicating that incomplete
 
1099
 * data is being examined. The function automatically sets SMP_OPT_ITERATE. This
 
1100
 * function only computes the condition, it does not apply the polarity required
 
1101
 * by IF/UNLESS, it's up to the caller to do this using something like this :
1294
1102
 *
1295
1103
 *     res = acl_pass(res);
1296
 
 *     if (res == ACL_PAT_MISS)
 
1104
 *     if (res == ACL_TEST_MISS)
1297
1105
 *         return 0;
1298
1106
 *     if (cond->pol == ACL_COND_UNLESS)
1299
1107
 *         res = !res;
1300
1108
 */
1301
 
int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, void *l7, int dir)
 
1109
enum acl_test_res acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, void *l7, unsigned int opt)
1302
1110
{
1303
1111
        __label__ fetch_next;
1304
1112
        struct acl_term_suite *suite;
1305
1113
        struct acl_term *term;
1306
1114
        struct acl_expr *expr;
1307
1115
        struct acl *acl;
1308
 
        struct acl_pattern *pattern;
1309
 
        struct acl_test test;
1310
 
        int acl_res, suite_res, cond_res;
 
1116
        struct sample smp;
 
1117
        enum acl_test_res acl_res, suite_res, cond_res;
 
1118
 
 
1119
        /* ACLs are iterated over all values, so let's always set the flag to
 
1120
         * indicate this to the fetch functions.
 
1121
         */
 
1122
        opt |= SMP_OPT_ITERATE;
1311
1123
 
1312
1124
        /* We're doing a logical OR between conditions so we initialize to FAIL.
1313
1125
         * The MISS status is propagated down from the suites.
1314
1126
         */
1315
 
        cond_res = ACL_PAT_FAIL;
 
1127
        cond_res = ACL_TEST_FAIL;
1316
1128
        list_for_each_entry(suite, &cond->suites, list) {
1317
1129
                /* Evaluate condition suite <suite>. We stop at the first term
1318
 
                 * which returns ACL_PAT_FAIL. The MISS status is still propagated
 
1130
                 * which returns ACL_TEST_FAIL. The MISS status is still propagated
1319
1131
                 * in case of uncertainty in the result.
1320
1132
                 */
1321
1133
 
1322
1134
                /* we're doing a logical AND between terms, so we must set the
1323
1135
                 * initial value to PASS.
1324
1136
                 */
1325
 
                suite_res = ACL_PAT_PASS;
 
1137
                suite_res = ACL_TEST_PASS;
1326
1138
                list_for_each_entry(term, &suite->terms, list) {
1327
1139
                        acl = term->acl;
1328
1140
 
1333
1145
                        /* ACL result not cached. Let's scan all the expressions
1334
1146
                         * and use the first one to match.
1335
1147
                         */
1336
 
                        acl_res = ACL_PAT_FAIL;
 
1148
                        acl_res = ACL_TEST_FAIL;
1337
1149
                        list_for_each_entry(expr, &acl->expr, list) {
1338
1150
                                /* we need to reset context and flags */
1339
 
                                memset(&test, 0, sizeof(test));
 
1151
                                memset(&smp, 0, sizeof(smp));
1340
1152
                        fetch_next:
1341
 
                                if (!expr->kw->fetch(px, l4, l7, dir, expr, &test)) {
 
1153
                                if (!sample_process(px, l4, l7, opt, expr->smp, &smp)) {
1342
1154
                                        /* maybe we could not fetch because of missing data */
1343
 
                                        if (test.flags & ACL_TEST_F_MAY_CHANGE && dir & ACL_PARTIAL)
1344
 
                                                acl_res |= ACL_PAT_MISS;
 
1155
                                        if (smp.flags & SMP_F_MAY_CHANGE && !(opt & SMP_OPT_FINAL))
 
1156
                                                acl_res |= ACL_TEST_MISS;
1345
1157
                                        continue;
1346
1158
                                }
1347
1159
 
1348
 
                                if (test.flags & ACL_TEST_F_RES_SET) {
1349
 
                                        if (test.flags & ACL_TEST_F_RES_PASS)
1350
 
                                                acl_res |= ACL_PAT_PASS;
1351
 
                                        else
1352
 
                                                acl_res |= ACL_PAT_FAIL;
1353
 
                                }
1354
 
                                else {
1355
 
                                        if (!eb_is_empty(&expr->pattern_tree)) {
1356
 
                                                /* a tree is present, let's check what type it is */
1357
 
                                                if (expr->kw->match == acl_match_str)
1358
 
                                                        acl_res |= acl_lookup_str(&test, expr) ? ACL_PAT_PASS : ACL_PAT_FAIL;
1359
 
                                                else if (expr->kw->match == acl_match_ip)
1360
 
                                                        acl_res |= acl_lookup_ip(&test, expr) ? ACL_PAT_PASS : ACL_PAT_FAIL;
1361
 
                                        }
1362
 
 
1363
 
                                        /* call the match() function for all tests on this value */
1364
 
                                        list_for_each_entry(pattern, &expr->patterns, list) {
1365
 
                                                if (acl_res == ACL_PAT_PASS)
1366
 
                                                        break;
1367
 
                                                acl_res |= expr->kw->match(&test, pattern);
1368
 
                                        }
1369
 
 
1370
 
                                        if ((test.flags & ACL_TEST_F_NULL_MATCH) &&
1371
 
                                            LIST_ISEMPTY(&expr->patterns) && eb_is_empty(&expr->pattern_tree))
1372
 
                                                acl_res |= expr->kw->match(&test, NULL);
1373
 
                                }
 
1160
                                acl_res |= pat2acl(pattern_exec_match(&expr->pat, &smp, 0));
1374
1161
                                /*
1375
1162
                                 * OK now acl_res holds the result of this expression
1376
 
                                 * as one of ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
 
1163
                                 * as one of ACL_TEST_FAIL, ACL_TEST_MISS or ACL_TEST_PASS.
1377
1164
                                 *
1378
1165
                                 * Then if (!MISS) we can cache the result, and put
1379
 
                                 * (test.flags & ACL_TEST_F_VOLATILE) in the cache flags.
 
1166
                                 * (smp.flags & SMP_F_VOLATILE) in the cache flags.
1380
1167
                                 *
1381
1168
                                 * FIXME: implement cache.
1382
1169
                                 *
1383
1170
                                 */
1384
1171
 
1385
 
                                /* now we may have some cleanup to do */
1386
 
                                if (test.flags & ACL_TEST_F_MUST_FREE) {
1387
 
                                        free(test.ptr);
1388
 
                                        test.len = 0;
1389
 
                                }
1390
 
 
1391
1172
                                /* we're ORing these terms, so a single PASS is enough */
1392
 
                                if (acl_res == ACL_PAT_PASS)
 
1173
                                if (acl_res == ACL_TEST_PASS)
1393
1174
                                        break;
1394
1175
 
1395
 
                                if (test.flags & ACL_TEST_F_FETCH_MORE)
 
1176
                                if (smp.flags & SMP_F_NOT_LAST)
1396
1177
                                        goto fetch_next;
1397
1178
 
1398
1179
                                /* sometimes we know the fetched data is subject to change
1399
1180
                                 * later and give another chance for a new match (eg: request
1400
1181
                                 * size, time, ...)
1401
1182
                                 */
1402
 
                                if (test.flags & ACL_TEST_F_MAY_CHANGE && dir & ACL_PARTIAL)
1403
 
                                        acl_res |= ACL_PAT_MISS;
 
1183
                                if (smp.flags & SMP_F_MAY_CHANGE && !(opt & SMP_OPT_FINAL))
 
1184
                                        acl_res |= ACL_TEST_MISS;
1404
1185
                        }
1405
1186
                        /*
1406
1187
                         * Here we have the result of an ACL (cached or not).
1412
1193
 
1413
1194
                        suite_res &= acl_res;
1414
1195
 
1415
 
                        /* we're ANDing these terms, so a single FAIL is enough */
1416
 
                        if (suite_res == ACL_PAT_FAIL)
 
1196
                        /* we're ANDing these terms, so a single FAIL or MISS is enough */
 
1197
                        if (suite_res != ACL_TEST_PASS)
1417
1198
                                break;
1418
1199
                }
1419
1200
                cond_res |= suite_res;
1420
1201
 
1421
1202
                /* we're ORing these terms, so a single PASS is enough */
1422
 
                if (cond_res == ACL_PAT_PASS)
 
1203
                if (cond_res == ACL_TEST_PASS)
1423
1204
                        break;
1424
1205
        }
1425
1206
        return cond_res;
1426
1207
}
1427
1208
 
1428
 
 
1429
 
/* Reports a pointer to the first ACL used in condition <cond> which requires
1430
 
 * at least one of the USE_FLAGS in <require>. Returns NULL if none matches.
1431
 
 * The construct is almost the same as for acl_exec_cond() since we're walking
1432
 
 * down the ACL tree as well. It is important that the tree is really walked
1433
 
 * through and never cached, because that way, this function can be used as a
1434
 
 * late check.
 
1209
/* Returns a pointer to the first ACL conflicting with usage at place <where>
 
1210
 * which is one of the SMP_VAL_* bits indicating a check place, or NULL if
 
1211
 * no conflict is found. Only full conflicts are detected (ACL is not usable).
 
1212
 * Use the next function to check for useless keywords.
1435
1213
 */
1436
 
struct acl *cond_find_require(const struct acl_cond *cond, unsigned int require)
 
1214
const struct acl *acl_cond_conflicts(const struct acl_cond *cond, unsigned int where)
1437
1215
{
1438
1216
        struct acl_term_suite *suite;
1439
1217
        struct acl_term *term;
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))
1446
1224
                                return acl;
1447
1225
                }
1448
1226
        }
1449
1227
        return NULL;
1450
1228
}
1451
1229
 
 
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
 
1234
 * returned.
 
1235
 */
 
1236
int acl_cond_kw_conflicts(const struct acl_cond *cond, unsigned int where, struct acl const **acl, char const **kw)
 
1237
{
 
1238
        struct acl_term_suite *suite;
 
1239
        struct acl_term *term;
 
1240
        struct acl_expr *expr;
 
1241
 
 
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)) {
 
1246
                                        if (acl)
 
1247
                                                *acl = term->acl;
 
1248
                                        if (kw)
 
1249
                                                *kw = expr->kw;
 
1250
                                        return 1;
 
1251
                                }
 
1252
                        }
 
1253
                }
 
1254
        }
 
1255
        return 0;
 
1256
}
 
1257
 
1452
1258
/*
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()).
1455
1262
 */
1456
 
int
1457
 
acl_find_targets(struct proxy *p)
 
1263
int acl_find_targets(struct proxy *p)
1458
1264
{
1459
1265
 
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;
1465
1271
 
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) {
1469
 
                                struct proxy *px;
1470
 
                                struct server *srv;
1471
 
                                char *pname, *sname;
1472
 
 
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);
1476
 
                                        cfgerr++;
1477
 
                                        continue;
1478
 
                                }
1479
 
 
1480
 
                                pname = expr->arg.str;
1481
 
                                sname = strrchr(pname, '/');
1482
 
 
1483
 
                                if (sname)
1484
 
                                        *sname++ = '\0';
1485
 
                                else {
1486
 
                                        sname = pname;
1487
 
                                        pname = NULL;
1488
 
                                }
1489
 
 
1490
 
                                px = p;
1491
 
                                if (pname) {
1492
 
                                        px = findproxy(pname, PR_CAP_BE);
1493
 
                                        if (!px) {
1494
 
                                                Alert("proxy %s: acl %s %s(): unable to find proxy '%s'.\n",
1495
 
                                                      p->id, acl->name, expr->kw->kw, pname);
1496
 
                                                cfgerr++;
1497
 
                                                continue;
1498
 
                                        }
1499
 
                                }
1500
 
 
1501
 
                                srv = findserver(px, sname);
1502
 
                                if (!srv) {
1503
 
                                        Alert("proxy %s: acl %s %s(): unable to find server '%s'.\n",
1504
 
                                              p->id, acl->name, expr->kw->kw, sname);
1505
 
                                        cfgerr++;
1506
 
                                        continue;
1507
 
                                }
1508
 
 
1509
 
                                free(expr->arg.str);
1510
 
                                expr->arg_len = 0;
1511
 
                                expr->arg.srv = srv;
1512
 
                                continue;
1513
 
                        }
1514
 
 
1515
 
                        if (strstr(expr->kw->kw, "http_auth") == expr->kw->kw) {
1516
 
 
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);
1520
 
                                        cfgerr++;
1521
 
                                        continue;
1522
 
                                }
1523
 
 
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;
1527
 
                                else
1528
 
                                        ul = auth_find_userlist(expr->arg.str);
1529
 
 
1530
 
                                if (!ul) {
1531
 
                                        Alert("proxy %s: acl %s %s(%s): unable to find userlist.\n",
1532
 
                                                p->id, acl->name, expr->kw->kw, expr->arg.str);
1533
 
                                        cfgerr++;
1534
 
                                        continue;
1535
 
                                }
1536
 
 
1537
 
                                expr->arg_len = 0;
1538
 
                                expr->arg.ul  = ul;
1539
 
                        }
1540
 
 
1541
 
 
1542
 
                        if (!strcmp(expr->kw->kw, "http_auth_group")) {
1543
 
 
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().
 
1277
                                 */
 
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);
 
1281
                                        cfgerr++;
 
1282
                                        continue;
 
1283
                                }
 
1284
 
 
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);
1547
1288
                                        cfgerr++;
1548
1289
                                        continue;
1549
1290
                                }
1550
1291
 
1551
 
                                list_for_each_entry(pattern, &expr->patterns, list) {
1552
 
                                        pattern->val.group_mask = auth_resolve_groups(expr->arg.ul, pattern->ptr.str);
1553
 
 
1554
 
                                        free(pattern->ptr.str);
1555
 
                                        pattern->ptr.str = NULL;
1556
 
                                        pattern->len = 0;
1557
 
 
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);
1561
1297
                                                cfgerr++;
1562
1298
                                                continue;
1563
1299
                                        }
 
1300
 
 
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);
 
1306
                                                        cfgerr++;
 
1307
                                                }
 
1308
                                        }
1564
1309
                                }
1565
1310
                        }
1566
1311
                }
1569
1314
        return cfgerr;
1570
1315
}
1571
1316
 
1572
 
/************************************************************************/
1573
 
/*             All supported keywords must be declared here.            */
1574
 
/************************************************************************/
1575
 
 
1576
 
/* Note: must not be declared <const> as its list will be overwritten */
1577
 
static struct acl_kw_list acl_kws = {{ },{
1578
 
        { "always_true", acl_parse_nothing, acl_fetch_true, acl_match_nothing,   ACL_USE_NOTHING },
1579
 
        { "always_false", acl_parse_nothing, acl_fetch_false, acl_match_nothing, ACL_USE_NOTHING },
1580
 
        { "wait_end", acl_parse_nothing, acl_fetch_wait_end, acl_match_nothing,  ACL_USE_NOTHING },
1581
 
#if 0
1582
 
        { "time",       acl_parse_time,  acl_fetch_time,   acl_match_time  },
1583
 
#endif
1584
 
        { NULL, NULL, NULL, NULL }
 
1317
/* initializes ACLs by resolving the sample fetch names they rely upon.
 
1318
 * Returns 0 on success, otherwise an error.
 
1319
 */
 
1320
int init_acl()
 
1321
{
 
1322
        int err = 0;
 
1323
        int index;
 
1324
        const char *name;
 
1325
        struct acl_kw_list *kwl;
 
1326
        struct sample_fetch *smp;
 
1327
 
 
1328
        list_for_each_entry(kwl, &acl_keywords.list, list) {
 
1329
                for (index = 0; kwl->kw[index].kw != NULL; index++) {
 
1330
                        name = kwl->kw[index].fetch_kw;
 
1331
                        if (!name)
 
1332
                                name = kwl->kw[index].kw;
 
1333
 
 
1334
                        smp = find_sample_fetch(name, strlen(name));
 
1335
                        if (!smp) {
 
1336
                                Alert("Critical internal error: ACL keyword '%s' relies on sample fetch '%s' which was not registered!\n",
 
1337
                                      kwl->kw[index].kw, name);
 
1338
                                err++;
 
1339
                                continue;
 
1340
                        }
 
1341
                        kwl->kw[index].smp = smp;
 
1342
                }
 
1343
        }
 
1344
        return err;
 
1345
}
 
1346
 
 
1347
/************************************************************************/
 
1348
/*      All supported sample and ACL keywords must be declared here.    */
 
1349
/************************************************************************/
 
1350
 
 
1351
/* Note: must not be declared <const> as its list will be overwritten.
 
1352
 * Please take care of keeping this list alphabetically sorted.
 
1353
 */
 
1354
static struct acl_kw_list acl_kws = {ILH, {
 
1355
        { /* END */ },
1585
1356
}};
1586
1357
 
1587
 
 
1588
1358
__attribute__((constructor))
1589
1359
static void __acl_init(void)
1590
1360
{