19
19
#include <common/standard.h>
20
20
#include <common/uri_auth.h>
22
#include <types/global.h>
22
24
#include <proto/acl.h>
23
25
#include <proto/auth.h>
24
26
#include <proto/log.h>
27
#include <proto/proxy.h>
26
31
/* The capabilities of filtering hooks describe the type of information
27
32
* available to each of them.
128
133
return ACL_PAT_FAIL;
136
/* Lookup a string in the expression's pattern tree. The node is returned if it
137
* exists, otherwise NULL.
139
void *acl_lookup_str(struct acl_test *test, struct acl_expr *expr)
141
/* data are stored in a tree */
142
struct ebmb_node *node;
145
/* we may have to force a trailing zero on the test pattern */
146
prev = test->ptr[test->len];
148
test->ptr[test->len] = '\0';
149
node = ebst_lookup(&expr->pattern_tree, test->ptr);
151
test->ptr[test->len] = prev;
131
155
/* Executes a regex. It needs to change the data. If it is marked READ_ONLY
132
156
* then it will be allocated and duplicated in place so that others may use
133
157
* it later on. Note that this is embarrassing because we always try to avoid
321
345
return ACL_PAT_FAIL;
348
/* Lookup an IPv4 address in the expression's pattern tree using the longest
349
* match method. The node is returned if it exists, otherwise NULL.
351
void *acl_lookup_ip(struct acl_test *test, struct acl_expr *expr)
355
if (test->i != AF_INET)
358
s = (void *)test->ptr;
360
return ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
324
363
/* Parse a string. It is allocated and duplicated. */
325
364
int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque)
329
368
len = strlen(*text);
370
if (pattern->flags & ACL_PAT_F_TREE_OK) {
371
/* we're allowed to put the data in a tree whose root is pointed
374
struct ebmb_node *node;
376
node = calloc(1, sizeof(*node) + len + 1);
379
memcpy(node->key, *text, len + 1);
380
if (ebst_insert(pattern->val.tree, node) != node)
381
free(node); /* was a duplicate */
382
pattern->flags |= ACL_PAT_F_TREE; /* this pattern now contains a tree */
330
386
pattern->ptr.str = strdup(*text);
331
387
if (!pattern->ptr.str)
569
625
int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque)
571
if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask))
627
struct eb_root *tree = NULL;
628
if (pattern->flags & ACL_PAT_F_TREE_OK)
629
tree = pattern->val.tree;
631
if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask)) {
632
unsigned int mask = ntohl(pattern->val.ipv4.mask.s_addr);
633
struct ebmb_node *node;
634
/* check if the mask is contiguous so that we can insert the
635
* network into the tree. A continuous mask has only ones on
636
* the left. This means that this mask + its lower bit added
637
* once again is null.
639
if (mask + (mask & -mask) == 0 && tree) {
640
mask = mask ? 33 - flsnz(mask & -mask) : 0; /* equals cidr value */
641
/* FIXME: insert <addr>/<mask> into the tree here */
642
node = calloc(1, sizeof(*node) + 4); /* reserve 4 bytes for IPv4 address */
645
memcpy(node->key, &pattern->val.ipv4.addr, 4); /* network byte order */
646
node->node.pfx = mask;
647
if (ebmb_insert_prefix(tree, node, 4) != node)
648
free(node); /* was a duplicate */
649
pattern->flags |= ACL_PAT_F_TREE;
648
729
free_pattern(pat);
732
static void free_pattern_tree(struct eb_root *root)
734
struct eb_node *node, *next;
735
node = eb_first(root);
737
next = eb_next(node);
651
743
static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
653
745
free_pattern_list(&expr->patterns);
746
free_pattern_tree(&expr->pattern_tree);
654
747
LIST_INIT(&expr->patterns);
655
748
if (expr->arg_len && expr->arg.str)
656
749
free(expr->arg.str);
754
static int acl_read_patterns_from_file( struct acl_keyword *aclkw,
755
struct acl_expr *expr,
756
const char *filename, int patflags)
761
struct acl_pattern *pattern;
764
file = fopen(filename, "r");
768
/* now parse all patterns. The file may contain only one pattern per
769
* line. If the line contains spaces, they will be part of the pattern.
770
* The pattern stops at the first CR, LF or EOF encountered.
775
while (fgets(trash, sizeof(trash), file) != NULL) {
779
/* ignore lines beginning with a dash */
783
/* strip leading spaces and tabs */
784
while (*c == ' ' || *c == '\t')
787
/* empty lines are ignored too */
792
while (*c && *c != '\n' && *c != '\r')
796
/* we keep the previous pattern along iterations as long as it's not used */
798
pattern = (struct acl_pattern *)malloc(sizeof(*pattern));
802
memset(pattern, 0, sizeof(*pattern));
803
pattern->flags = patflags;
805
if ((aclkw->requires & ACL_MAY_LOOKUP) && !(pattern->flags & ACL_PAT_F_IGNORE_CASE)) {
806
/* we pre-set the data pointer to the tree's head so that functions
807
* which are able to insert in a tree know where to do that.
809
pattern->flags |= ACL_PAT_F_TREE_OK;
810
pattern->val.tree = &expr->pattern_tree;
813
if (!aclkw->parse(args, pattern, &opaque))
814
goto out_free_pattern;
816
/* if the parser did not feed the tree, let's chain the pattern to the list */
817
if (!(pattern->flags & ACL_PAT_F_TREE)) {
818
LIST_ADDQ(&expr->patterns, &pattern->list);
819
pattern = NULL; /* get a new one */
823
free_pattern(pattern);
827
free_pattern(pattern);
661
833
/* Parse an ACL expression starting at <args>[0], and return it.
662
834
* Right now, the only accepted syntax is :
663
835
* <subject> [<value>...]
711
884
while (**args == '-') {
712
885
if ((*args)[1] == 'i')
713
886
patflags |= ACL_PAT_F_IGNORE_CASE;
714
else if ((*args)[1] == 'f')
715
patflags |= ACL_PAT_F_FROM_FILE;
887
else if ((*args)[1] == 'f') {
888
if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE))
716
892
else if ((*args)[1] == '-') {
1140
1316
acl_res |= ACL_PAT_FAIL;
1319
if (!eb_is_empty(&expr->pattern_tree)) {
1320
/* a tree is present, let's check what type it is */
1321
if (expr->kw->match == acl_match_str)
1322
acl_res |= acl_lookup_str(&test, expr) ? ACL_PAT_PASS : ACL_PAT_FAIL;
1323
else if (expr->kw->match == acl_match_ip)
1324
acl_res |= acl_lookup_ip(&test, expr) ? ACL_PAT_PASS : ACL_PAT_FAIL;
1143
1327
/* call the match() function for all tests on this value */
1144
1328
list_for_each_entry(pattern, &expr->patterns, list) {
1145
acl_res |= expr->kw->match(&test, pattern);
1146
1329
if (acl_res == ACL_PAT_PASS)
1331
acl_res |= expr->kw->match(&test, pattern);
1150
if ((test.flags & ACL_TEST_F_NULL_MATCH) && LIST_ISEMPTY(&expr->patterns))
1334
if ((test.flags & ACL_TEST_F_NULL_MATCH) &&
1335
LIST_ISEMPTY(&expr->patterns) && eb_is_empty(&expr->pattern_tree))
1151
1336
acl_res |= expr->kw->match(&test, NULL);
1245
1430
list_for_each_entry(acl, &p->acl, list) {
1246
1431
list_for_each_entry(expr, &acl->expr, list) {
1432
if (strcmp(expr->kw->kw, "srv_is_up") == 0) {
1435
char *pname, *sname;
1437
if (!expr->arg.str || !*expr->arg.str) {
1438
Alert("proxy %s: acl %s %s(): missing server name.\n",
1439
p->id, acl->name, expr->kw->kw);
1444
pname = expr->arg.str;
1445
sname = strrchr(pname, '/');
1456
px = findproxy(pname, PR_CAP_BE);
1458
Alert("proxy %s: acl %s %s(): unable to find proxy '%s'.\n",
1459
p->id, acl->name, expr->kw->kw, pname);
1465
srv = findserver(px, sname);
1467
Alert("proxy %s: acl %s %s(): unable to find server '%s'.\n",
1468
p->id, acl->name, expr->kw->kw, sname);
1473
free(expr->arg.str);
1475
expr->arg.srv = srv;
1247
1479
if (strstr(expr->kw->kw, "http_auth") == expr->kw->kw) {
1249
1481
if (!expr->arg.str || !*expr->arg.str) {