~ubuntu-branches/debian/sid/haproxy/sid

« back to all changes in this revision

Viewing changes to .pc/from-upstream/0006-BUG-MEDIUM-pattern-don-t-load-more-than-once-a-patte.patch/src/acl.c

  • Committer: Package Import Robot
  • Author(s): Vincent Bernat
  • Date: 2014-12-07 11:11:21 UTC
  • Revision ID: package-import@ubuntu.com-20141207111121-qgifv7nl6eoi3lek
Tags: 1.5.8-2
* Cherry-pick the following patches from 1.5.9 release:
    - 8a0b93bde77e BUG/MAJOR: sessions: unlink session from list on out
                              of memory
    - bae03eaad40a BUG/MEDIUM: pattern: don't load more than once a pattern
                               list.
    - 93637b6e8503 BUG/MEDIUM: connection: sanitize PPv2 header length before
                               parsing address information
    - 8ba50128832b BUG/MAJOR: frontend: initialize capture pointers earlier
    - 1f96a87c4e14 BUG/MEDIUM: checks: fix conflicts between agent checks and
                               ssl healthchecks
    - 9bcc01ae2598 BUG/MEDIUM: ssl: force a full GC in case of memory shortage
    - 909514970089 BUG/MEDIUM: ssl: fix bad ssl context init can cause
                               segfault in case of OOM.
* Cherry-pick the following patches from future 1.5.10 release:
    - 1e89acb6be9b BUG/MEDIUM: payload: ensure that a request channel is
                               available
    - bad3c6f1b6d7 BUG/MEDIUM: patterns: previous fix was incomplete

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ACL management functions.
 
3
 *
 
4
 * Copyright 2000-2013 Willy Tarreau <w@1wt.eu>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public License
 
8
 * as published by the Free Software Foundation; either version
 
9
 * 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 */
 
12
 
 
13
#include <ctype.h>
 
14
#include <stdio.h>
 
15
#include <string.h>
 
16
 
 
17
#include <common/config.h>
 
18
#include <common/mini-clist.h>
 
19
#include <common/standard.h>
 
20
#include <common/uri_auth.h>
 
21
 
 
22
#include <types/global.h>
 
23
 
 
24
#include <proto/acl.h>
 
25
#include <proto/arg.h>
 
26
#include <proto/auth.h>
 
27
#include <proto/channel.h>
 
28
#include <proto/log.h>
 
29
#include <proto/pattern.h>
 
30
#include <proto/proxy.h>
 
31
#include <proto/sample.h>
 
32
#include <proto/stick_table.h>
 
33
 
 
34
#include <ebsttree.h>
 
35
 
 
36
/* List head of all known ACL keywords */
 
37
static struct acl_kw_list acl_keywords = {
 
38
        .list = LIST_HEAD_INIT(acl_keywords.list)
 
39
};
 
40
 
 
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;
 
48
}
 
49
 
 
50
/*
 
51
 * Registers the ACL keyword list <kwl> as a list of valid keywords for next
 
52
 * parsing sessions.
 
53
 */
 
54
void acl_register_keywords(struct acl_kw_list *kwl)
 
55
{
 
56
        LIST_ADDQ(&acl_keywords.list, &kwl->list);
 
57
}
 
58
 
 
59
/*
 
60
 * Unregisters the ACL keyword list <kwl> from the list of valid keywords.
 
61
 */
 
62
void acl_unregister_keywords(struct acl_kw_list *kwl)
 
63
{
 
64
        LIST_DEL(&kwl->list);
 
65
        LIST_INIT(&kwl->list);
 
66
}
 
67
 
 
68
/* Return a pointer to the ACL <name> within the list starting at <head>, or
 
69
 * NULL if not found.
 
70
 */
 
71
struct acl *find_acl_by_name(const char *name, struct list *head)
 
72
{
 
73
        struct acl *acl;
 
74
        list_for_each_entry(acl, head, list) {
 
75
                if (strcmp(acl->name, name) == 0)
 
76
                        return acl;
 
77
        }
 
78
        return NULL;
 
79
}
 
80
 
 
81
/* Return a pointer to the ACL keyword <kw>, or NULL if not found. Note that if
 
82
 * <kw> contains an opening parenthesis or a comma, only the left part of it is
 
83
 * checked.
 
84
 */
 
85
struct acl_keyword *find_acl_kw(const char *kw)
 
86
{
 
87
        int index;
 
88
        const char *kwend;
 
89
        struct acl_kw_list *kwl;
 
90
 
 
91
        kwend = kw;
 
92
        while (*kwend && *kwend != '(' && *kwend != ',')
 
93
                kwend++;
 
94
 
 
95
        list_for_each_entry(kwl, &acl_keywords.list, list) {
 
96
                for (index = 0; kwl->kw[index].kw != NULL; index++) {
 
97
                        if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
 
98
                            kwl->kw[index].kw[kwend-kw] == 0)
 
99
                                return &kwl->kw[index];
 
100
                }
 
101
        }
 
102
        return NULL;
 
103
}
 
104
 
 
105
static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
 
106
{
 
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);
 
123
        return expr;
 
124
}
 
125
 
 
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
 *
 
131
 * Right now, the only accepted syntax is :
 
132
 * <subject> [<value>...]
 
133
 */
 
134
struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *al,
 
135
                                const char *file, int line)
 
136
{
 
137
        __label__ out_return, out_free_expr;
 
138
        struct acl_expr *expr;
 
139
        struct acl_keyword *aclkw;
 
140
        int patflags;
 
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
        int cur_type;
 
149
        int nbargs;
 
150
        int operator = STD_OP_EQ;
 
151
        int op;
 
152
        int contain_colon, have_dot;
 
153
        const char *dot;
 
154
        signed long long value, minor;
 
155
        /* The following buffer contain two numbers, a ':' separator and the final \0. */
 
156
        char buffer[NB_LLMAX_STR + 1 + NB_LLMAX_STR + 1];
 
157
        int is_loaded;
 
158
        int unique_id;
 
159
        char *error;
 
160
        struct pat_ref *ref;
 
161
        struct pattern_expr *pattern_expr;
 
162
        int load_as_map = 0;
 
163
        int acl_conv_found = 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;
 
173
 
 
174
        aclkw = find_acl_kw(args[0]);
 
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
                 * If we find any converter, then we don't use the ACL keyword's match
 
233
                 * anymore but the one related to the converter's output type.
 
234
                 */
 
235
                cur_type = smp->fetch->out_type;
 
236
                while (*arg) {
 
237
                        struct sample_conv *conv;
 
238
                        struct sample_conv_expr *conv_expr;
 
239
 
 
240
                        if (*arg == ')') /* skip last closing parenthesis */
 
241
                                arg++;
 
242
 
 
243
                        if (*arg && *arg != ',') {
 
244
                                if (ckw)
 
245
                                        memprintf(err, "ACL keyword '%s' : missing comma after conv keyword '%s'.",
 
246
                                                  aclkw->kw, ckw);
 
247
                                else
 
248
                                        memprintf(err, "ACL keyword '%s' : missing comma after fetch keyword.",
 
249
                                                  aclkw->kw);
 
250
                                goto out_free_smp;
 
251
                        }
 
252
 
 
253
                        while (*arg == ',') /* then trailing commas */
 
254
                                arg++;
 
255
 
 
256
                        begw = arg; /* start of conv keyword */
 
257
 
 
258
                        if (!*begw)
 
259
                                /* none ? end of converters */
 
260
                                break;
 
261
 
 
262
                        for (endw = begw; *endw && *endw != '(' && *endw != ','; endw++);
 
263
 
 
264
                        free(ckw);
 
265
                        ckw = my_strndup(begw, endw - begw);
 
266
 
 
267
                        conv = find_sample_conv(begw, endw - begw);
 
268
                        if (!conv) {
 
269
                                /* Unknown converter method */
 
270
                                memprintf(err, "ACL keyword '%s' : unknown conv method '%s'.",
 
271
                                          aclkw->kw, ckw);
 
272
                                goto out_free_smp;
 
273
                        }
 
274
 
 
275
                        arg = endw;
 
276
                        if (*arg == '(') {
 
277
                                /* look for the end of this term */
 
278
                                while (*arg && *arg != ')')
 
279
                                        arg++;
 
280
                                if (*arg != ')') {
 
281
                                        memprintf(err, "ACL keyword '%s' : syntax error: missing ')' after conv keyword '%s'.",
 
282
                                                  aclkw->kw, ckw);
 
283
                                        goto out_free_smp;
 
284
                                }
 
285
                        }
 
286
 
 
287
                        if (conv->in_type >= SMP_TYPES || conv->out_type >= SMP_TYPES) {
 
288
                                memprintf(err, "ACL keyword '%s' : returns type of conv method '%s' is unknown.",
 
289
                                          aclkw->kw, ckw);
 
290
                                goto out_free_smp;
 
291
                        }
 
292
 
 
293
                        /* If impossible type conversion */
 
294
                        if (!sample_casts[cur_type][conv->in_type]) {
 
295
                                memprintf(err, "ACL keyword '%s' : conv method '%s' cannot be applied.",
 
296
                                          aclkw->kw, ckw);
 
297
                                goto out_free_smp;
 
298
                        }
 
299
 
 
300
                        cur_type = conv->out_type;
 
301
                        conv_expr = calloc(1, sizeof(struct sample_conv_expr));
 
302
                        if (!conv_expr)
 
303
                                goto out_free_smp;
 
304
 
 
305
                        LIST_ADDQ(&(smp->conv_exprs), &(conv_expr->list));
 
306
                        conv_expr->conv = conv;
 
307
                        acl_conv_found = 1;
 
308
 
 
309
                        if (arg != endw) {
 
310
                                int err_arg;
 
311
 
 
312
                                if (!conv->arg_mask) {
 
313
                                        memprintf(err, "ACL keyword '%s' : conv method '%s' does not support any args.",
 
314
                                                  aclkw->kw, ckw);
 
315
                                        goto out_free_smp;
 
316
                                }
 
317
 
 
318
                                al->kw = smp->fetch->kw;
 
319
                                al->conv = conv_expr->conv->kw;
 
320
                                if (make_arg_list(endw + 1, arg - endw - 1, conv->arg_mask, &conv_expr->arg_p, err, NULL, &err_arg, al) < 0) {
 
321
                                        memprintf(err, "ACL keyword '%s' : invalid arg %d in conv method '%s' : %s.",
 
322
                                                  aclkw->kw, err_arg+1, ckw, *err);
 
323
                                        goto out_free_smp;
 
324
                                }
 
325
 
 
326
                                if (!conv_expr->arg_p)
 
327
                                        conv_expr->arg_p = empty_arg_list;
 
328
 
 
329
                                if (conv->val_args && !conv->val_args(conv_expr->arg_p, conv, file, line, err)) {
 
330
                                        memprintf(err, "ACL keyword '%s' : invalid args in conv method '%s' : %s.",
 
331
                                                  aclkw->kw, ckw, *err);
 
332
                                        goto out_free_smp;
 
333
                                }
 
334
                        }
 
335
                        else if (ARGM(conv->arg_mask)) {
 
336
                                memprintf(err, "ACL keyword '%s' : missing args for conv method '%s'.",
 
337
                                          aclkw->kw, ckw);
 
338
                                goto out_free_smp;
 
339
                        }
 
340
                }
 
341
        }
 
342
        else {
 
343
                /* This is not an ACL keyword, so we hope this is a sample fetch
 
344
                 * keyword that we're going to transparently use as an ACL. If
 
345
                 * so, we retrieve a completely parsed expression with args and
 
346
                 * convs already done.
 
347
                 */
 
348
                smp = sample_parse_expr((char **)args, &idx, file, line, err, al);
 
349
                if (!smp) {
 
350
                        memprintf(err, "%s in ACL expression '%s'", *err, *args);
 
351
                        goto out_return;
 
352
                }
 
353
                cur_type = smp_expr_output_type(smp);
 
354
        }
 
355
 
 
356
        expr = (struct acl_expr *)calloc(1, sizeof(*expr));
 
357
        if (!expr) {
 
358
                memprintf(err, "out of memory when parsing ACL expression");
 
359
                goto out_return;
 
360
        }
 
361
 
 
362
        pattern_init_head(&expr->pat);
 
363
 
 
364
        expr->pat.expect_type = cur_type;
 
365
        expr->smp             = smp;
 
366
        expr->kw              = smp->fetch->kw;
 
367
        smp = NULL; /* don't free it anymore */
 
368
 
 
369
        if (aclkw && !acl_conv_found) {
 
370
                expr->kw = aclkw->kw;
 
371
                expr->pat.parse  = aclkw->parse  ? aclkw->parse  : pat_parse_fcts[aclkw->match_type];
 
372
                expr->pat.index  = aclkw->index  ? aclkw->index  : pat_index_fcts[aclkw->match_type];
 
373
                expr->pat.match  = aclkw->match  ? aclkw->match  : pat_match_fcts[aclkw->match_type];
 
374
                expr->pat.delete = aclkw->delete ? aclkw->delete : pat_delete_fcts[aclkw->match_type];
 
375
                expr->pat.prune  = aclkw->prune  ? aclkw->prune  : pat_prune_fcts[aclkw->match_type];
 
376
        }
 
377
 
 
378
        if (!expr->pat.parse) {
 
379
                /* Parse/index/match functions depend on the expression type,
 
380
                 * so we have to map them now. Some types can be automatically
 
381
                 * converted.
 
382
                 */
 
383
                switch (cur_type) {
 
384
                case SMP_T_BOOL:
 
385
                        expr->pat.parse = pat_parse_fcts[PAT_MATCH_BOOL];
 
386
                        expr->pat.index = pat_index_fcts[PAT_MATCH_BOOL];
 
387
                        expr->pat.match = pat_match_fcts[PAT_MATCH_BOOL];
 
388
                        expr->pat.delete = pat_delete_fcts[PAT_MATCH_BOOL];
 
389
                        expr->pat.prune = pat_prune_fcts[PAT_MATCH_BOOL];
 
390
                        expr->pat.expect_type = pat_match_types[PAT_MATCH_BOOL];
 
391
                        break;
 
392
                case SMP_T_SINT:
 
393
                case SMP_T_UINT:
 
394
                        expr->pat.parse = pat_parse_fcts[PAT_MATCH_INT];
 
395
                        expr->pat.index = pat_index_fcts[PAT_MATCH_INT];
 
396
                        expr->pat.match = pat_match_fcts[PAT_MATCH_INT];
 
397
                        expr->pat.delete = pat_delete_fcts[PAT_MATCH_INT];
 
398
                        expr->pat.prune = pat_prune_fcts[PAT_MATCH_INT];
 
399
                        expr->pat.expect_type = pat_match_types[PAT_MATCH_INT];
 
400
                        break;
 
401
                case SMP_T_IPV4:
 
402
                case SMP_T_IPV6:
 
403
                        expr->pat.parse = pat_parse_fcts[PAT_MATCH_IP];
 
404
                        expr->pat.index = pat_index_fcts[PAT_MATCH_IP];
 
405
                        expr->pat.match = pat_match_fcts[PAT_MATCH_IP];
 
406
                        expr->pat.delete = pat_delete_fcts[PAT_MATCH_IP];
 
407
                        expr->pat.prune = pat_prune_fcts[PAT_MATCH_IP];
 
408
                        expr->pat.expect_type = pat_match_types[PAT_MATCH_IP];
 
409
                        break;
 
410
                case SMP_T_STR:
 
411
                        expr->pat.parse = pat_parse_fcts[PAT_MATCH_STR];
 
412
                        expr->pat.index = pat_index_fcts[PAT_MATCH_STR];
 
413
                        expr->pat.match = pat_match_fcts[PAT_MATCH_STR];
 
414
                        expr->pat.delete = pat_delete_fcts[PAT_MATCH_STR];
 
415
                        expr->pat.prune = pat_prune_fcts[PAT_MATCH_STR];
 
416
                        expr->pat.expect_type = pat_match_types[PAT_MATCH_STR];
 
417
                        break;
 
418
                }
 
419
        }
 
420
 
 
421
        /* Additional check to protect against common mistakes */
 
422
        if (expr->pat.parse && cur_type != SMP_T_BOOL && !*args[1]) {
 
423
                Warning("parsing acl keyword '%s' :\n"
 
424
                        "  no pattern to match against were provided, so this ACL will never match.\n"
 
425
                        "  If this is what you intended, please add '--' to get rid of this warning.\n"
 
426
                        "  If you intended to match only for existence, please use '-m found'.\n"
 
427
                        "  If you wanted to force an int to match as a bool, please use '-m bool'.\n"
 
428
                        "\n",
 
429
                        args[0]);
 
430
        }
 
431
 
 
432
        args++;
 
433
 
 
434
        /* check for options before patterns. Supported options are :
 
435
         *   -i : ignore case for all patterns by default
 
436
         *   -f : read patterns from those files
 
437
         *   -m : force matching method (must be used before -f)
 
438
         *   -M : load the file as map file
 
439
         *   -u : force the unique id of the acl
 
440
         *   -- : everything after this is not an option
 
441
         */
 
442
        patflags = 0;
 
443
        is_loaded = 0;
 
444
        unique_id = -1;
 
445
        while (**args == '-') {
 
446
                if (strcmp(*args, "-i") == 0)
 
447
                        patflags |= PAT_MF_IGNORE_CASE;
 
448
                else if (strcmp(*args, "-n") == 0)
 
449
                        patflags |= PAT_MF_NO_DNS;
 
450
                else if (strcmp(*args, "-u") == 0) {
 
451
                        unique_id = strtol(args[1], &error, 10);
 
452
                        if (*error != '\0') {
 
453
                                memprintf(err, "the argument of -u must be an integer");
 
454
                                goto out_free_expr;
 
455
                        }
 
456
 
 
457
                        /* Check if this id is really unique. */
 
458
                        if (pat_ref_lookupid(unique_id)) {
 
459
                                memprintf(err, "the id is already used");
 
460
                                goto out_free_expr;
 
461
                        }
 
462
 
 
463
                        args++;
 
464
                }
 
465
                else if (strcmp(*args, "-f") == 0) {
 
466
                        if (!expr->pat.parse) {
 
467
                                memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
 
468
                                goto out_free_expr;
 
469
                        }
 
470
 
 
471
                        if (!pattern_read_from_file(&expr->pat, PAT_REF_ACL, args[1], patflags, load_as_map, err, file, line))
 
472
                                goto out_free_expr;
 
473
                        is_loaded = 1;
 
474
                        args++;
 
475
                }
 
476
                else if (strcmp(*args, "-m") == 0) {
 
477
                        int idx;
 
478
 
 
479
                        if (is_loaded) {
 
480
                                memprintf(err, "'-m' must only be specified before patterns and files in parsing ACL expression");
 
481
                                goto out_free_expr;
 
482
                        }
 
483
 
 
484
                        idx = pat_find_match_name(args[1]);
 
485
                        if (idx < 0) {
 
486
                                memprintf(err, "unknown matching method '%s' when parsing ACL expression", args[1]);
 
487
                                goto out_free_expr;
 
488
                        }
 
489
 
 
490
                        /* Note: -m found is always valid, bool/int are compatible, str/bin/reg/len are compatible */
 
491
                        if (!sample_casts[cur_type][pat_match_types[idx]]) {
 
492
                                memprintf(err, "matching method '%s' cannot be used with fetch keyword '%s'", args[1], expr->kw);
 
493
                                goto out_free_expr;
 
494
                        }
 
495
                        expr->pat.parse = pat_parse_fcts[idx];
 
496
                        expr->pat.index = pat_index_fcts[idx];
 
497
                        expr->pat.match = pat_match_fcts[idx];
 
498
                        expr->pat.delete = pat_delete_fcts[idx];
 
499
                        expr->pat.prune = pat_prune_fcts[idx];
 
500
                        expr->pat.expect_type = pat_match_types[idx];
 
501
                        args++;
 
502
                }
 
503
                else if (strcmp(*args, "-M") == 0) {
 
504
                        load_as_map = 1;
 
505
                }
 
506
                else if (strcmp(*args, "--") == 0) {
 
507
                        args++;
 
508
                        break;
 
509
                }
 
510
                else {
 
511
                        memprintf(err, "'%s' is not a valid ACL option. Please use '--' before any pattern beginning with a '-'", args[0]);
 
512
                        goto out_free_expr;
 
513
                        break;
 
514
                }
 
515
                args++;
 
516
        }
 
517
 
 
518
        if (!expr->pat.parse) {
 
519
                memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
 
520
                goto out_free_expr;
 
521
        }
 
522
 
 
523
        /* Create displayed reference */
 
524
        snprintf(trash.str, trash.size, "acl '%s' file '%s' line %d", expr->kw, file, line);
 
525
        trash.str[trash.size - 1] = '\0';
 
526
 
 
527
        /* Create new patern reference. */
 
528
        ref = pat_ref_newid(unique_id, trash.str, PAT_REF_ACL);
 
529
        if (!ref) {
 
530
                memprintf(err, "memory error");
 
531
                goto out_free_expr;
 
532
        }
 
533
 
 
534
        /* Create new pattern expression associated to this reference. */
 
535
        pattern_expr = pattern_new_expr(&expr->pat, ref, err);
 
536
        if (!pattern_expr)
 
537
                goto out_free_expr;
 
538
 
 
539
        /* Copy the pattern matching and indexing flags. */
 
540
        pattern_expr->mflags = patflags;
 
541
 
 
542
        /* now parse all patterns */
 
543
        while (**args) {
 
544
                arg = *args;
 
545
 
 
546
                /* Compatibility layer. Each pattern can parse only one string per pattern,
 
547
                 * but the pat_parser_int() and pat_parse_dotted_ver() parsers were need
 
548
                 * optionnaly two operators. The first operator is the match method: eq,
 
549
                 * le, lt, ge and gt. pat_parse_int() and pat_parse_dotted_ver() functions
 
550
                 * can have a compatibility syntax based on ranges:
 
551
                 *
 
552
                 * pat_parse_int():
 
553
                 *
 
554
                 *   "eq x" -> "x" or "x:x"
 
555
                 *   "le x" -> ":x"
 
556
                 *   "lt x" -> ":y" (with y = x - 1)
 
557
                 *   "ge x" -> "x:"
 
558
                 *   "gt x" -> "y:" (with y = x + 1)
 
559
                 *
 
560
                 * pat_parse_dotted_ver():
 
561
                 *
 
562
                 *   "eq x.y" -> "x.y" or "x.y:x.y"
 
563
                 *   "le x.y" -> ":x.y"
 
564
                 *   "lt x.y" -> ":w.z" (with w.z = x.y - 1)
 
565
                 *   "ge x.y" -> "x.y:"
 
566
                 *   "gt x.y" -> "w.z:" (with w.z = x.y + 1)
 
567
                 *
 
568
                 * If y is not present, assume that is "0".
 
569
                 *
 
570
                 * The syntax eq, le, lt, ge and gt are proper to the acl syntax. The
 
571
                 * following block of code detect the operator, and rewrite each value
 
572
                 * in parsable string.
 
573
                 */
 
574
                if (expr->pat.parse == pat_parse_int ||
 
575
                    expr->pat.parse == pat_parse_dotted_ver) {
 
576
                        /* Check for operator. If the argument is operator, memorise it and
 
577
                         * continue to the next argument.
 
578
                         */
 
579
                        op = get_std_op(arg);
 
580
                        if (op != -1) {
 
581
                                operator = op;
 
582
                                args++;
 
583
                                continue;
 
584
                        }
 
585
 
 
586
                        /* Check if the pattern contain ':' or '-' character. */
 
587
                        contain_colon = (strchr(arg, ':') || strchr(arg, '-'));
 
588
 
 
589
                        /* If the pattern contain ':' or '-' character, give it to the parser as is.
 
590
                         * If no contain ':' and operator is STD_OP_EQ, give it to the parser as is.
 
591
                         * In other case, try to convert the value according with the operator.
 
592
                         */
 
593
                        if (!contain_colon && operator != STD_OP_EQ) {
 
594
                                /* Search '.' separator. */
 
595
                                dot = strchr(arg, '.');
 
596
                                if (!dot) {
 
597
                                        have_dot = 0;
 
598
                                        minor = 0;
 
599
                                        dot = arg + strlen(arg);
 
600
                                }
 
601
                                else
 
602
                                        have_dot = 1;
 
603
 
 
604
                                /* convert the integer minor part for the pat_parse_dotted_ver() function. */
 
605
                                if (expr->pat.parse == pat_parse_dotted_ver && have_dot) {
 
606
                                        if (strl2llrc(dot+1, strlen(dot+1), &minor) != 0) {
 
607
                                                memprintf(err, "'%s' is neither a number nor a supported operator", arg);
 
608
                                                goto out_free_expr;
 
609
                                        }
 
610
                                        if (minor >= 65536) {
 
611
                                                memprintf(err, "'%s' contains too large a minor value", arg);
 
612
                                                goto out_free_expr;
 
613
                                        }
 
614
                                }
 
615
 
 
616
                                /* convert the integer value for the pat_parse_int() function, and the
 
617
                                 * integer major part for the pat_parse_dotted_ver() function.
 
618
                                 */
 
619
                                if (strl2llrc(arg, dot - arg, &value) != 0) {
 
620
                                        memprintf(err, "'%s' is neither a number nor a supported operator", arg);
 
621
                                        goto out_free_expr;
 
622
                                }
 
623
                                if (expr->pat.parse == pat_parse_dotted_ver)  {
 
624
                                        if (value >= 65536) {
 
625
                                                memprintf(err, "'%s' contains too large a major value", arg);
 
626
                                                goto out_free_expr;
 
627
                                        }
 
628
                                        value = (value << 16) | (minor & 0xffff);
 
629
                                }
 
630
 
 
631
                                switch (operator) {
 
632
 
 
633
                                case STD_OP_EQ: /* this case is not possible. */
 
634
                                        memprintf(err, "internal error");
 
635
                                        goto out_free_expr;
 
636
 
 
637
                                case STD_OP_GT:
 
638
                                        value++; /* gt = ge + 1 */
 
639
 
 
640
                                case STD_OP_GE:
 
641
                                        if (expr->pat.parse == pat_parse_int)
 
642
                                                snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, "%lld:", value);
 
643
                                        else
 
644
                                                snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, "%lld.%lld:",
 
645
                                                         value >> 16, value & 0xffff);
 
646
                                        arg = buffer;
 
647
                                        break;
 
648
 
 
649
                                case STD_OP_LT:
 
650
                                        value--; /* lt = le - 1 */
 
651
 
 
652
                                case STD_OP_LE:
 
653
                                        if (expr->pat.parse == pat_parse_int)
 
654
                                                snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, ":%lld", value);
 
655
                                        else
 
656
                                                snprintf(buffer, NB_LLMAX_STR+NB_LLMAX_STR+2, ":%lld.%lld",
 
657
                                                         value >> 16, value & 0xffff);
 
658
                                        arg = buffer;
 
659
                                        break;
 
660
                                }
 
661
                        }
 
662
                }
 
663
 
 
664
                /* Add sample to the reference, and try to compile it fior each pattern
 
665
                 * using this value.
 
666
                 */
 
667
                if (!pat_ref_add(ref, arg, NULL, err))
 
668
                        goto out_free_expr;
 
669
                args++;
 
670
        }
 
671
 
 
672
        return expr;
 
673
 
 
674
 out_free_expr:
 
675
        prune_acl_expr(expr);
 
676
        free(expr);
 
677
        free(ckw);
 
678
 out_free_smp:
 
679
        free(smp);
 
680
 out_return:
 
681
        return NULL;
 
682
}
 
683
 
 
684
/* Purge everything in the acl <acl>, then return <acl>. */
 
685
struct acl *prune_acl(struct acl *acl) {
 
686
 
 
687
        struct acl_expr *expr, *exprb;
 
688
 
 
689
        free(acl->name);
 
690
 
 
691
        list_for_each_entry_safe(expr, exprb, &acl->expr, list) {
 
692
                LIST_DEL(&expr->list);
 
693
                prune_acl_expr(expr);
 
694
                free(expr);
 
695
        }
 
696
 
 
697
        return acl;
 
698
}
 
699
 
 
700
/* Parse an ACL with the name starting at <args>[0], and with a list of already
 
701
 * known ACLs in <acl>. If the ACL was not in the list, it will be added.
 
702
 * A pointer to that ACL is returned. If the ACL has an empty name, then it's
 
703
 * an anonymous one and it won't be merged with any other one. If <err> is not
 
704
 * NULL, it will be filled with an appropriate error. This pointer must be
 
705
 * freeable or NULL. <al> is the arg_list serving as a head for unresolved
 
706
 * dependencies.
 
707
 *
 
708
 * args syntax: <aclname> <acl_expr>
 
709
 */
 
710
struct acl *parse_acl(const char **args, struct list *known_acl, char **err, struct arg_list *al,
 
711
                      const char *file, int line)
 
712
{
 
713
        __label__ out_return, out_free_acl_expr, out_free_name;
 
714
        struct acl *cur_acl;
 
715
        struct acl_expr *acl_expr;
 
716
        char *name;
 
717
        const char *pos;
 
718
 
 
719
        if (**args && (pos = invalid_char(*args))) {
 
720
                memprintf(err, "invalid character in ACL name : '%c'", *pos);
 
721
                goto out_return;
 
722
        }
 
723
 
 
724
        acl_expr = parse_acl_expr(args + 1, err, al, file, line);
 
725
        if (!acl_expr) {
 
726
                /* parse_acl_expr will have filled <err> here */
 
727
                goto out_return;
 
728
        }
 
729
 
 
730
        /* Check for args beginning with an opening parenthesis just after the
 
731
         * subject, as this is almost certainly a typo. Right now we can only
 
732
         * emit a warning, so let's do so.
 
733
         */
 
734
        if (!strchr(args[1], '(') && *args[2] == '(')
 
735
                Warning("parsing acl '%s' :\n"
 
736
                        "  matching '%s' for pattern '%s' is likely a mistake and probably\n"
 
737
                        "  not what you want. Maybe you need to remove the extraneous space before '('.\n"
 
738
                        "  If you are really sure this is not an error, please insert '--' between the\n"
 
739
                        "  match and the pattern to make this warning message disappear.\n",
 
740
                        args[0], args[1], args[2]);
 
741
 
 
742
        if (*args[0])
 
743
                cur_acl = find_acl_by_name(args[0], known_acl);
 
744
        else
 
745
                cur_acl = NULL;
 
746
 
 
747
        if (!cur_acl) {
 
748
                name = strdup(args[0]);
 
749
                if (!name) {
 
750
                        memprintf(err, "out of memory when parsing ACL");
 
751
                        goto out_free_acl_expr;
 
752
                }
 
753
                cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
 
754
                if (cur_acl == NULL) {
 
755
                        memprintf(err, "out of memory when parsing ACL");
 
756
                        goto out_free_name;
 
757
                }
 
758
 
 
759
                LIST_INIT(&cur_acl->expr);
 
760
                LIST_ADDQ(known_acl, &cur_acl->list);
 
761
                cur_acl->name = name;
 
762
        }
 
763
 
 
764
        /* We want to know what features the ACL needs (typically HTTP parsing),
 
765
         * and where it may be used. If an ACL relies on multiple matches, it is
 
766
         * OK if at least one of them may match in the context where it is used.
 
767
         */
 
768
        cur_acl->use |= acl_expr->smp->fetch->use;
 
769
        cur_acl->val |= acl_expr->smp->fetch->val;
 
770
        LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
 
771
        return cur_acl;
 
772
 
 
773
 out_free_name:
 
774
        free(name);
 
775
 out_free_acl_expr:
 
776
        prune_acl_expr(acl_expr);
 
777
        free(acl_expr);
 
778
 out_return:
 
779
        return NULL;
 
780
}
 
781
 
 
782
/* Some useful ACLs provided by default. Only those used are allocated. */
 
783
 
 
784
const struct {
 
785
        const char *name;
 
786
        const char *expr[4]; /* put enough for longest expression */
 
787
} default_acl_list[] = {
 
788
        { .name = "TRUE",           .expr = {"always_true",""}},
 
789
        { .name = "FALSE",          .expr = {"always_false",""}},
 
790
        { .name = "LOCALHOST",      .expr = {"src","127.0.0.1/8",""}},
 
791
        { .name = "HTTP",           .expr = {"req_proto_http",""}},
 
792
        { .name = "HTTP_1.0",       .expr = {"req_ver","1.0",""}},
 
793
        { .name = "HTTP_1.1",       .expr = {"req_ver","1.1",""}},
 
794
        { .name = "METH_CONNECT",   .expr = {"method","CONNECT",""}},
 
795
        { .name = "METH_GET",       .expr = {"method","GET","HEAD",""}},
 
796
        { .name = "METH_HEAD",      .expr = {"method","HEAD",""}},
 
797
        { .name = "METH_OPTIONS",   .expr = {"method","OPTIONS",""}},
 
798
        { .name = "METH_POST",      .expr = {"method","POST",""}},
 
799
        { .name = "METH_TRACE",     .expr = {"method","TRACE",""}},
 
800
        { .name = "HTTP_URL_ABS",   .expr = {"url_reg","^[^/:]*://",""}},
 
801
        { .name = "HTTP_URL_SLASH", .expr = {"url_beg","/",""}},
 
802
        { .name = "HTTP_URL_STAR",  .expr = {"url","*",""}},
 
803
        { .name = "HTTP_CONTENT",   .expr = {"hdr_val(content-length)","gt","0",""}},
 
804
        { .name = "RDP_COOKIE",     .expr = {"req_rdp_cookie_cnt","gt","0",""}},
 
805
        { .name = "REQ_CONTENT",    .expr = {"req_len","gt","0",""}},
 
806
        { .name = "WAIT_END",       .expr = {"wait_end",""}},
 
807
        { .name = NULL, .expr = {""}}
 
808
};
 
809
 
 
810
/* Find a default ACL from the default_acl list, compile it and return it.
 
811
 * If the ACL is not found, NULL is returned. In theory, it cannot fail,
 
812
 * except when default ACLs are broken, in which case it will return NULL.
 
813
 * If <known_acl> is not NULL, the ACL will be queued at its tail. If <err> is
 
814
 * not NULL, it will be filled with an error message if an error occurs. This
 
815
 * pointer must be freeable or NULL. <al> is an arg_list serving as a list head
 
816
 * to report missing dependencies.
 
817
 */
 
818
static struct acl *find_acl_default(const char *acl_name, struct list *known_acl,
 
819
                                    char **err, struct arg_list *al,
 
820
                                    const char *file, int line)
 
821
{
 
822
        __label__ out_return, out_free_acl_expr, out_free_name;
 
823
        struct acl *cur_acl;
 
824
        struct acl_expr *acl_expr;
 
825
        char *name;
 
826
        int index;
 
827
 
 
828
        for (index = 0; default_acl_list[index].name != NULL; index++) {
 
829
                if (strcmp(acl_name, default_acl_list[index].name) == 0)
 
830
                        break;
 
831
        }
 
832
 
 
833
        if (default_acl_list[index].name == NULL) {
 
834
                memprintf(err, "no such ACL : '%s'", acl_name);
 
835
                return NULL;
 
836
        }
 
837
 
 
838
        acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr, err, al, file, line);
 
839
        if (!acl_expr) {
 
840
                /* parse_acl_expr must have filled err here */
 
841
                goto out_return;
 
842
        }
 
843
 
 
844
        name = strdup(acl_name);
 
845
        if (!name) {
 
846
                memprintf(err, "out of memory when building default ACL '%s'", acl_name);
 
847
                goto out_free_acl_expr;
 
848
        }
 
849
 
 
850
        cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
 
851
        if (cur_acl == NULL) {
 
852
                memprintf(err, "out of memory when building default ACL '%s'", acl_name);
 
853
                goto out_free_name;
 
854
        }
 
855
 
 
856
        cur_acl->name = name;
 
857
        cur_acl->use |= acl_expr->smp->fetch->use;
 
858
        cur_acl->val |= acl_expr->smp->fetch->val;
 
859
        LIST_INIT(&cur_acl->expr);
 
860
        LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
 
861
        if (known_acl)
 
862
                LIST_ADDQ(known_acl, &cur_acl->list);
 
863
 
 
864
        return cur_acl;
 
865
 
 
866
 out_free_name:
 
867
        free(name);
 
868
 out_free_acl_expr:
 
869
        prune_acl_expr(acl_expr);
 
870
        free(acl_expr);
 
871
 out_return:
 
872
        return NULL;
 
873
}
 
874
 
 
875
/* Purge everything in the acl_cond <cond>, then return <cond>. */
 
876
struct acl_cond *prune_acl_cond(struct acl_cond *cond)
 
877
{
 
878
        struct acl_term_suite *suite, *tmp_suite;
 
879
        struct acl_term *term, *tmp_term;
 
880
 
 
881
        /* iterate through all term suites and free all terms and all suites */
 
882
        list_for_each_entry_safe(suite, tmp_suite, &cond->suites, list) {
 
883
                list_for_each_entry_safe(term, tmp_term, &suite->terms, list)
 
884
                        free(term);
 
885
                free(suite);
 
886
        }
 
887
        return cond;
 
888
}
 
889
 
 
890
/* Parse an ACL condition starting at <args>[0], relying on a list of already
 
891
 * known ACLs passed in <known_acl>. The new condition is returned (or NULL in
 
892
 * case of low memory). Supports multiple conditions separated by "or". If
 
893
 * <err> is not NULL, it will be filled with a pointer to an error message in
 
894
 * case of error, that the caller is responsible for freeing. The initial
 
895
 * location must either be freeable or NULL. The list <al> serves as a list head
 
896
 * for unresolved dependencies.
 
897
 */
 
898
struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl,
 
899
                                enum acl_cond_pol pol, char **err, struct arg_list *al,
 
900
                                const char *file, int line)
 
901
{
 
902
        __label__ out_return, out_free_suite, out_free_term;
 
903
        int arg, neg;
 
904
        const char *word;
 
905
        struct acl *cur_acl;
 
906
        struct acl_term *cur_term;
 
907
        struct acl_term_suite *cur_suite;
 
908
        struct acl_cond *cond;
 
909
        unsigned int suite_val;
 
910
 
 
911
        cond = (struct acl_cond *)calloc(1, sizeof(*cond));
 
912
        if (cond == NULL) {
 
913
                memprintf(err, "out of memory when parsing condition");
 
914
                goto out_return;
 
915
        }
 
916
 
 
917
        LIST_INIT(&cond->list);
 
918
        LIST_INIT(&cond->suites);
 
919
        cond->pol = pol;
 
920
        cond->val = 0;
 
921
 
 
922
        cur_suite = NULL;
 
923
        suite_val = ~0U;
 
924
        neg = 0;
 
925
        for (arg = 0; *args[arg]; arg++) {
 
926
                word = args[arg];
 
927
 
 
928
                /* remove as many exclamation marks as we can */
 
929
                while (*word == '!') {
 
930
                        neg = !neg;
 
931
                        word++;
 
932
                }
 
933
 
 
934
                /* an empty word is allowed because we cannot force the user to
 
935
                 * always think about not leaving exclamation marks alone.
 
936
                 */
 
937
                if (!*word)
 
938
                        continue;
 
939
 
 
940
                if (strcasecmp(word, "or") == 0 || strcmp(word, "||") == 0) {
 
941
                        /* new term suite */
 
942
                        cond->val |= suite_val;
 
943
                        suite_val = ~0U;
 
944
                        cur_suite = NULL;
 
945
                        neg = 0;
 
946
                        continue;
 
947
                }
 
948
 
 
949
                if (strcmp(word, "{") == 0) {
 
950
                        /* we may have a complete ACL expression between two braces,
 
951
                         * find the last one.
 
952
                         */
 
953
                        int arg_end = arg + 1;
 
954
                        const char **args_new;
 
955
 
 
956
                        while (*args[arg_end] && strcmp(args[arg_end], "}") != 0)
 
957
                                arg_end++;
 
958
 
 
959
                        if (!*args[arg_end]) {
 
960
                                memprintf(err, "missing closing '}' in condition");
 
961
                                goto out_free_suite;
 
962
                        }
 
963
 
 
964
                        args_new = calloc(1, (arg_end - arg + 1) * sizeof(*args_new));
 
965
                        if (!args_new) {
 
966
                                memprintf(err, "out of memory when parsing condition");
 
967
                                goto out_free_suite;
 
968
                        }
 
969
 
 
970
                        args_new[0] = "";
 
971
                        memcpy(args_new + 1, args + arg + 1, (arg_end - arg) * sizeof(*args_new));
 
972
                        args_new[arg_end - arg] = "";
 
973
                        cur_acl = parse_acl(args_new, known_acl, err, al, file, line);
 
974
                        free(args_new);
 
975
 
 
976
                        if (!cur_acl) {
 
977
                                /* note that parse_acl() must have filled <err> here */
 
978
                                goto out_free_suite;
 
979
                        }
 
980
                        word = args[arg + 1];
 
981
                        arg = arg_end;
 
982
                }
 
983
                else {
 
984
                        /* search for <word> in the known ACL names. If we do not find
 
985
                         * it, let's look for it in the default ACLs, and if found, add
 
986
                         * it to the list of ACLs of this proxy. This makes it possible
 
987
                         * to override them.
 
988
                         */
 
989
                        cur_acl = find_acl_by_name(word, known_acl);
 
990
                        if (cur_acl == NULL) {
 
991
                                cur_acl = find_acl_default(word, known_acl, err, al, file, line);
 
992
                                if (cur_acl == NULL) {
 
993
                                        /* note that find_acl_default() must have filled <err> here */
 
994
                                        goto out_free_suite;
 
995
                                }
 
996
                        }
 
997
                }
 
998
 
 
999
                cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term));
 
1000
                if (cur_term == NULL) {
 
1001
                        memprintf(err, "out of memory when parsing condition");
 
1002
                        goto out_free_suite;
 
1003
                }
 
1004
 
 
1005
                cur_term->acl = cur_acl;
 
1006
                cur_term->neg = neg;
 
1007
 
 
1008
                /* Here it is a bit complex. The acl_term_suite is a conjunction
 
1009
                 * of many terms. It may only be used if all of its terms are
 
1010
                 * usable at the same time. So the suite's validity domain is an
 
1011
                 * AND between all ACL keywords' ones. But, the global condition
 
1012
                 * is valid if at least one term suite is OK. So it's an OR between
 
1013
                 * all of their validity domains. We could emit a warning as soon
 
1014
                 * as suite_val is null because it means that the last ACL is not
 
1015
                 * compatible with the previous ones. Let's remain simple for now.
 
1016
                 */
 
1017
                cond->use |= cur_acl->use;
 
1018
                suite_val &= cur_acl->val;
 
1019
 
 
1020
                if (!cur_suite) {
 
1021
                        cur_suite = (struct acl_term_suite *)calloc(1, sizeof(*cur_suite));
 
1022
                        if (cur_suite == NULL) {
 
1023
                                memprintf(err, "out of memory when parsing condition");
 
1024
                                goto out_free_term;
 
1025
                        }
 
1026
                        LIST_INIT(&cur_suite->terms);
 
1027
                        LIST_ADDQ(&cond->suites, &cur_suite->list);
 
1028
                }
 
1029
                LIST_ADDQ(&cur_suite->terms, &cur_term->list);
 
1030
                neg = 0;
 
1031
        }
 
1032
 
 
1033
        cond->val |= suite_val;
 
1034
        return cond;
 
1035
 
 
1036
 out_free_term:
 
1037
        free(cur_term);
 
1038
 out_free_suite:
 
1039
        prune_acl_cond(cond);
 
1040
        free(cond);
 
1041
 out_return:
 
1042
        return NULL;
 
1043
}
 
1044
 
 
1045
/* Builds an ACL condition starting at the if/unless keyword. The complete
 
1046
 * condition is returned. NULL is returned in case of error or if the first
 
1047
 * word is neither "if" nor "unless". It automatically sets the file name and
 
1048
 * the line number in the condition for better error reporting, and sets the
 
1049
 * HTTP intiailization requirements in the proxy. If <err> is not NULL, it will
 
1050
 * be filled with a pointer to an error message in case of error, that the
 
1051
 * caller is responsible for freeing. The initial location must either be
 
1052
 * freeable or NULL.
 
1053
 */
 
1054
struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args, char **err)
 
1055
{
 
1056
        enum acl_cond_pol pol = ACL_COND_NONE;
 
1057
        struct acl_cond *cond = NULL;
 
1058
 
 
1059
        if (err)
 
1060
                *err = NULL;
 
1061
 
 
1062
        if (!strcmp(*args, "if")) {
 
1063
                pol = ACL_COND_IF;
 
1064
                args++;
 
1065
        }
 
1066
        else if (!strcmp(*args, "unless")) {
 
1067
                pol = ACL_COND_UNLESS;
 
1068
                args++;
 
1069
        }
 
1070
        else {
 
1071
                memprintf(err, "conditions must start with either 'if' or 'unless'");
 
1072
                return NULL;
 
1073
        }
 
1074
 
 
1075
        cond = parse_acl_cond(args, &px->acl, pol, err, &px->conf.args, file, line);
 
1076
        if (!cond) {
 
1077
                /* note that parse_acl_cond must have filled <err> here */
 
1078
                return NULL;
 
1079
        }
 
1080
 
 
1081
        cond->file = file;
 
1082
        cond->line = line;
 
1083
        px->http_needed |= !!(cond->use & SMP_USE_HTTP_ANY);
 
1084
        return cond;
 
1085
}
 
1086
 
 
1087
/* Execute condition <cond> and return either ACL_TEST_FAIL, ACL_TEST_MISS or
 
1088
 * ACL_TEST_PASS depending on the test results. ACL_TEST_MISS may only be
 
1089
 * returned if <opt> does not contain SMP_OPT_FINAL, indicating that incomplete
 
1090
 * data is being examined. The function automatically sets SMP_OPT_ITERATE. This
 
1091
 * function only computes the condition, it does not apply the polarity required
 
1092
 * by IF/UNLESS, it's up to the caller to do this using something like this :
 
1093
 *
 
1094
 *     res = acl_pass(res);
 
1095
 *     if (res == ACL_TEST_MISS)
 
1096
 *         return 0;
 
1097
 *     if (cond->pol == ACL_COND_UNLESS)
 
1098
 *         res = !res;
 
1099
 */
 
1100
enum acl_test_res acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, void *l7, unsigned int opt)
 
1101
{
 
1102
        __label__ fetch_next;
 
1103
        struct acl_term_suite *suite;
 
1104
        struct acl_term *term;
 
1105
        struct acl_expr *expr;
 
1106
        struct acl *acl;
 
1107
        struct sample smp;
 
1108
        enum acl_test_res acl_res, suite_res, cond_res;
 
1109
 
 
1110
        /* ACLs are iterated over all values, so let's always set the flag to
 
1111
         * indicate this to the fetch functions.
 
1112
         */
 
1113
        opt |= SMP_OPT_ITERATE;
 
1114
 
 
1115
        /* We're doing a logical OR between conditions so we initialize to FAIL.
 
1116
         * The MISS status is propagated down from the suites.
 
1117
         */
 
1118
        cond_res = ACL_TEST_FAIL;
 
1119
        list_for_each_entry(suite, &cond->suites, list) {
 
1120
                /* Evaluate condition suite <suite>. We stop at the first term
 
1121
                 * which returns ACL_TEST_FAIL. The MISS status is still propagated
 
1122
                 * in case of uncertainty in the result.
 
1123
                 */
 
1124
 
 
1125
                /* we're doing a logical AND between terms, so we must set the
 
1126
                 * initial value to PASS.
 
1127
                 */
 
1128
                suite_res = ACL_TEST_PASS;
 
1129
                list_for_each_entry(term, &suite->terms, list) {
 
1130
                        acl = term->acl;
 
1131
 
 
1132
                        /* FIXME: use cache !
 
1133
                         * check acl->cache_idx for this.
 
1134
                         */
 
1135
 
 
1136
                        /* ACL result not cached. Let's scan all the expressions
 
1137
                         * and use the first one to match.
 
1138
                         */
 
1139
                        acl_res = ACL_TEST_FAIL;
 
1140
                        list_for_each_entry(expr, &acl->expr, list) {
 
1141
                                /* we need to reset context and flags */
 
1142
                                memset(&smp, 0, sizeof(smp));
 
1143
                        fetch_next:
 
1144
                                if (!sample_process(px, l4, l7, opt, expr->smp, &smp)) {
 
1145
                                        /* maybe we could not fetch because of missing data */
 
1146
                                        if (smp.flags & SMP_F_MAY_CHANGE && !(opt & SMP_OPT_FINAL))
 
1147
                                                acl_res |= ACL_TEST_MISS;
 
1148
                                        continue;
 
1149
                                }
 
1150
 
 
1151
                                acl_res |= pat2acl(pattern_exec_match(&expr->pat, &smp, 0));
 
1152
                                /*
 
1153
                                 * OK now acl_res holds the result of this expression
 
1154
                                 * as one of ACL_TEST_FAIL, ACL_TEST_MISS or ACL_TEST_PASS.
 
1155
                                 *
 
1156
                                 * Then if (!MISS) we can cache the result, and put
 
1157
                                 * (smp.flags & SMP_F_VOLATILE) in the cache flags.
 
1158
                                 *
 
1159
                                 * FIXME: implement cache.
 
1160
                                 *
 
1161
                                 */
 
1162
 
 
1163
                                /* we're ORing these terms, so a single PASS is enough */
 
1164
                                if (acl_res == ACL_TEST_PASS)
 
1165
                                        break;
 
1166
 
 
1167
                                if (smp.flags & SMP_F_NOT_LAST)
 
1168
                                        goto fetch_next;
 
1169
 
 
1170
                                /* sometimes we know the fetched data is subject to change
 
1171
                                 * later and give another chance for a new match (eg: request
 
1172
                                 * size, time, ...)
 
1173
                                 */
 
1174
                                if (smp.flags & SMP_F_MAY_CHANGE && !(opt & SMP_OPT_FINAL))
 
1175
                                        acl_res |= ACL_TEST_MISS;
 
1176
                        }
 
1177
                        /*
 
1178
                         * Here we have the result of an ACL (cached or not).
 
1179
                         * ACLs are combined, negated or not, to form conditions.
 
1180
                         */
 
1181
 
 
1182
                        if (term->neg)
 
1183
                                acl_res = acl_neg(acl_res);
 
1184
 
 
1185
                        suite_res &= acl_res;
 
1186
 
 
1187
                        /* we're ANDing these terms, so a single FAIL or MISS is enough */
 
1188
                        if (suite_res != ACL_TEST_PASS)
 
1189
                                break;
 
1190
                }
 
1191
                cond_res |= suite_res;
 
1192
 
 
1193
                /* we're ORing these terms, so a single PASS is enough */
 
1194
                if (cond_res == ACL_TEST_PASS)
 
1195
                        break;
 
1196
        }
 
1197
        return cond_res;
 
1198
}
 
1199
 
 
1200
/* Returns a pointer to the first ACL conflicting with usage at place <where>
 
1201
 * which is one of the SMP_VAL_* bits indicating a check place, or NULL if
 
1202
 * no conflict is found. Only full conflicts are detected (ACL is not usable).
 
1203
 * Use the next function to check for useless keywords.
 
1204
 */
 
1205
const struct acl *acl_cond_conflicts(const struct acl_cond *cond, unsigned int where)
 
1206
{
 
1207
        struct acl_term_suite *suite;
 
1208
        struct acl_term *term;
 
1209
        struct acl *acl;
 
1210
 
 
1211
        list_for_each_entry(suite, &cond->suites, list) {
 
1212
                list_for_each_entry(term, &suite->terms, list) {
 
1213
                        acl = term->acl;
 
1214
                        if (!(acl->val & where))
 
1215
                                return acl;
 
1216
                }
 
1217
        }
 
1218
        return NULL;
 
1219
}
 
1220
 
 
1221
/* Returns a pointer to the first ACL and its first keyword to conflict with
 
1222
 * usage at place <where> which is one of the SMP_VAL_* bits indicating a check
 
1223
 * place. Returns true if a conflict is found, with <acl> and <kw> set (if non
 
1224
 * null), or false if not conflict is found. The first useless keyword is
 
1225
 * returned.
 
1226
 */
 
1227
int acl_cond_kw_conflicts(const struct acl_cond *cond, unsigned int where, struct acl const **acl, char const **kw)
 
1228
{
 
1229
        struct acl_term_suite *suite;
 
1230
        struct acl_term *term;
 
1231
        struct acl_expr *expr;
 
1232
 
 
1233
        list_for_each_entry(suite, &cond->suites, list) {
 
1234
                list_for_each_entry(term, &suite->terms, list) {
 
1235
                        list_for_each_entry(expr, &term->acl->expr, list) {
 
1236
                                if (!(expr->smp->fetch->val & where)) {
 
1237
                                        if (acl)
 
1238
                                                *acl = term->acl;
 
1239
                                        if (kw)
 
1240
                                                *kw = expr->kw;
 
1241
                                        return 1;
 
1242
                                }
 
1243
                        }
 
1244
                }
 
1245
        }
 
1246
        return 0;
 
1247
}
 
1248
 
 
1249
/*
 
1250
 * Find targets for userlist and groups in acl. Function returns the number
 
1251
 * of errors or OK if everything is fine. It must be called only once sample
 
1252
 * fetch arguments have been resolved (after smp_resolve_args()).
 
1253
 */
 
1254
int acl_find_targets(struct proxy *p)
 
1255
{
 
1256
 
 
1257
        struct acl *acl;
 
1258
        struct acl_expr *expr;
 
1259
        struct pattern_list *pattern;
 
1260
        int cfgerr = 0;
 
1261
        struct pattern_expr_list *pexp;
 
1262
 
 
1263
        list_for_each_entry(acl, &p->acl, list) {
 
1264
                list_for_each_entry(expr, &acl->expr, list) {
 
1265
                        if (!strcmp(expr->kw, "http_auth_group")) {
 
1266
                                /* Note: the ARGT_USR argument may only have been resolved earlier
 
1267
                                 * by smp_resolve_args().
 
1268
                                 */
 
1269
                                if (expr->smp->arg_p->unresolved) {
 
1270
                                        Alert("Internal bug in proxy %s: %sacl %s %s() makes use of unresolved userlist '%s'. Please report this.\n",
 
1271
                                              p->id, *acl->name ? "" : "anonymous ", acl->name, expr->kw, expr->smp->arg_p->data.str.str);
 
1272
                                        cfgerr++;
 
1273
                                        continue;
 
1274
                                }
 
1275
 
 
1276
                                if (LIST_ISEMPTY(&expr->pat.head)) {
 
1277
                                        Alert("proxy %s: acl %s %s(): no groups specified.\n",
 
1278
                                                p->id, acl->name, expr->kw);
 
1279
                                        cfgerr++;
 
1280
                                        continue;
 
1281
                                }
 
1282
 
 
1283
                                /* For each pattern, check if the group exists. */
 
1284
                                list_for_each_entry(pexp, &expr->pat.head, list) {
 
1285
                                        if (LIST_ISEMPTY(&pexp->expr->patterns)) {
 
1286
                                                Alert("proxy %s: acl %s %s(): no groups specified.\n",
 
1287
                                                        p->id, acl->name, expr->kw);
 
1288
                                                cfgerr++;
 
1289
                                                continue;
 
1290
                                        }
 
1291
 
 
1292
                                        list_for_each_entry(pattern, &pexp->expr->patterns, list) {
 
1293
                                                /* this keyword only has one argument */
 
1294
                                                if (!check_group(expr->smp->arg_p->data.usr, pattern->pat.ptr.str)) {
 
1295
                                                        Alert("proxy %s: acl %s %s(): invalid group '%s'.\n",
 
1296
                                                              p->id, acl->name, expr->kw, pattern->pat.ptr.str);
 
1297
                                                        cfgerr++;
 
1298
                                                }
 
1299
                                        }
 
1300
                                }
 
1301
                        }
 
1302
                }
 
1303
        }
 
1304
 
 
1305
        return cfgerr;
 
1306
}
 
1307
 
 
1308
/* initializes ACLs by resolving the sample fetch names they rely upon.
 
1309
 * Returns 0 on success, otherwise an error.
 
1310
 */
 
1311
int init_acl()
 
1312
{
 
1313
        int err = 0;
 
1314
        int index;
 
1315
        const char *name;
 
1316
        struct acl_kw_list *kwl;
 
1317
        struct sample_fetch *smp;
 
1318
 
 
1319
        list_for_each_entry(kwl, &acl_keywords.list, list) {
 
1320
                for (index = 0; kwl->kw[index].kw != NULL; index++) {
 
1321
                        name = kwl->kw[index].fetch_kw;
 
1322
                        if (!name)
 
1323
                                name = kwl->kw[index].kw;
 
1324
 
 
1325
                        smp = find_sample_fetch(name, strlen(name));
 
1326
                        if (!smp) {
 
1327
                                Alert("Critical internal error: ACL keyword '%s' relies on sample fetch '%s' which was not registered!\n",
 
1328
                                      kwl->kw[index].kw, name);
 
1329
                                err++;
 
1330
                                continue;
 
1331
                        }
 
1332
                        kwl->kw[index].smp = smp;
 
1333
                }
 
1334
        }
 
1335
        return err;
 
1336
}
 
1337
 
 
1338
/************************************************************************/
 
1339
/*      All supported sample and ACL keywords must be declared here.    */
 
1340
/************************************************************************/
 
1341
 
 
1342
/* Note: must not be declared <const> as its list will be overwritten.
 
1343
 * Please take care of keeping this list alphabetically sorted.
 
1344
 */
 
1345
static struct acl_kw_list acl_kws = {ILH, {
 
1346
        { /* END */ },
 
1347
}};
 
1348
 
 
1349
__attribute__((constructor))
 
1350
static void __acl_init(void)
 
1351
{
 
1352
        acl_register_keywords(&acl_kws);
 
1353
}
 
1354
 
 
1355
 
 
1356
/*
 
1357
 * Local variables:
 
1358
 *  c-indent-level: 8
 
1359
 *  c-basic-offset: 8
 
1360
 * End:
 
1361
 */