~ubuntu-branches/ubuntu/utopic/haproxy/utopic-proposed

« back to all changes in this revision

Viewing changes to src/acl.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Cornet
  • Date: 2010-06-18 00:42:53 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20100618004253-ygka2bh6nblkhfj2
Tags: 1.4.8-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
#include <common/standard.h>
20
20
#include <common/uri_auth.h>
21
21
 
 
22
#include <types/global.h>
 
23
 
22
24
#include <proto/acl.h>
23
25
#include <proto/auth.h>
24
26
#include <proto/log.h>
 
27
#include <proto/proxy.h>
 
28
 
 
29
#include <ebsttree.h>
25
30
 
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;
129
134
}
130
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
 
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;
322
346
}
323
347
 
 
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.
 
350
 */
 
351
void *acl_lookup_ip(struct acl_test *test, struct acl_expr *expr)
 
352
{
 
353
        struct in_addr *s;
 
354
 
 
355
        if (test->i != AF_INET)
 
356
                return ACL_PAT_FAIL;
 
357
 
 
358
        s = (void *)test->ptr;
 
359
 
 
360
        return ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
 
361
}
 
362
 
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)
326
365
{
327
366
        int len;
328
367
 
329
368
        len  = strlen(*text);
 
369
 
 
370
        if (pattern->flags & ACL_PAT_F_TREE_OK) {
 
371
                /* we're allowed to put the data in a tree whose root is pointed
 
372
                 * to by val.tree.
 
373
                 */
 
374
                struct ebmb_node *node;
 
375
 
 
376
                node = calloc(1, sizeof(*node) + len + 1);
 
377
                if (!node)
 
378
                        return 0;
 
379
                memcpy(node->key, *text, len + 1);
 
380
                if (ebst_insert(pattern->val.tree, node) != node)
 
381
                        free(node); /* was a duplicate */
 
382
                pattern->flags |= ACL_PAT_F_TREE; /* this pattern now contains a tree */
 
383
                return 1;
 
384
        }
 
385
 
330
386
        pattern->ptr.str = strdup(*text);
331
387
        if (!pattern->ptr.str)
332
388
                return 0;
568
624
 */
569
625
int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque)
570
626
{
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;
 
630
 
 
631
        if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask)) {
 
632
                unsigned int mask = ntohl(pattern->val.ipv4.mask.s_addr);
 
633
                struct ebmb_node *node;
 
634
                /* check if the mask is contiguous so that we can insert the
 
635
                 * network into the tree. A continuous mask has only ones on
 
636
                 * the left. This means that this mask + its lower bit added
 
637
                 * once again is null.
 
638
                 */
 
639
                if (mask + (mask & -mask) == 0 && tree) {
 
640
                        mask = mask ? 33 - flsnz(mask & -mask) : 0; /* equals cidr value */
 
641
                        /* FIXME: insert <addr>/<mask> into the tree here */
 
642
                        node = calloc(1, sizeof(*node) + 4); /* reserve 4 bytes for IPv4 address */
 
643
                        if (!node)
 
644
                                return 0;
 
645
                        memcpy(node->key, &pattern->val.ipv4.addr, 4); /* network byte order */
 
646
                        node->node.pfx = mask;
 
647
                        if (ebmb_insert_prefix(tree, node, 4) != node)
 
648
                                free(node); /* was a duplicate */
 
649
                        pattern->flags |= ACL_PAT_F_TREE;
 
650
                        return 1;
 
651
                }
572
652
                return 1;
 
653
        }
573
654
        else
574
655
                return 0;
575
656
}
648
729
                free_pattern(pat);
649
730
}
650
731
 
 
732
static void free_pattern_tree(struct eb_root *root)
 
733
{
 
734
        struct eb_node *node, *next;
 
735
        node = eb_first(root);
 
736
        while (node) {
 
737
                next = eb_next(node);
 
738
                free(node);
 
739
                node = next;
 
740
        }
 
741
}
 
742
 
651
743
static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
652
744
{
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);
658
751
        return expr;
659
752
}
660
753
 
 
754
static int acl_read_patterns_from_file( struct acl_keyword *aclkw,
 
755
                                        struct acl_expr *expr,
 
756
                                        const char *filename, int patflags)
 
757
{
 
758
        FILE *file;
 
759
        char *c;
 
760
        const char *args[2];
 
761
        struct acl_pattern *pattern;
 
762
        int opaque;
 
763
 
 
764
        file = fopen(filename, "r");
 
765
        if (!file)
 
766
                return 0;
 
767
 
 
768
        /* now parse all patterns. The file may contain only one pattern per
 
769
         * line. If the line contains spaces, they will be part of the pattern.
 
770
         * The pattern stops at the first CR, LF or EOF encountered.
 
771
         */
 
772
        opaque = 0;
 
773
        pattern = NULL;
 
774
        args[1] = "";
 
775
        while (fgets(trash, sizeof(trash), file) != NULL) {
 
776
 
 
777
                c = trash;
 
778
 
 
779
                /* ignore lines beginning with a dash */
 
780
                if (*c == '#')
 
781
                        continue;
 
782
 
 
783
                /* strip leading spaces and tabs */
 
784
                while (*c == ' ' || *c == '\t')
 
785
                        c++;
 
786
 
 
787
                /* empty lines are ignored too */
 
788
                if (!*c)
 
789
                        continue;
 
790
 
 
791
                args[0] = c;
 
792
                while (*c && *c != '\n' && *c != '\r')
 
793
                        c++;
 
794
                *c = 0;
 
795
 
 
796
                /* we keep the previous pattern along iterations as long as it's not used */
 
797
                if (!pattern)
 
798
                        pattern = (struct acl_pattern *)malloc(sizeof(*pattern));
 
799
                if (!pattern)
 
800
                        goto out_close;
 
801
 
 
802
                memset(pattern, 0, sizeof(*pattern));
 
803
                pattern->flags = patflags;
 
804
 
 
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.
 
808
                         */
 
809
                        pattern->flags |= ACL_PAT_F_TREE_OK;
 
810
                        pattern->val.tree = &expr->pattern_tree;
 
811
                }
 
812
 
 
813
                if (!aclkw->parse(args, pattern, &opaque))
 
814
                        goto out_free_pattern;
 
815
 
 
816
                /* if the parser did not feed the tree, let's chain the pattern to the list */
 
817
                if (!(pattern->flags & ACL_PAT_F_TREE)) {
 
818
                        LIST_ADDQ(&expr->patterns, &pattern->list);
 
819
                        pattern = NULL; /* get a new one */
 
820
                }
 
821
        }
 
822
        if (pattern)
 
823
                free_pattern(pattern);
 
824
        return 1;
 
825
 
 
826
 out_free_pattern:
 
827
        free_pattern(pattern);
 
828
 out_close:
 
829
        fclose(file);
 
830
        return 0;
 
831
}
 
832
 
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>...]
682
854
        expr->kw = aclkw;
683
855
        aclkw->use_cnt++;
684
856
        LIST_INIT(&expr->patterns);
 
857
        expr->pattern_tree = EB_ROOT_UNIQUE;
685
858
        expr->arg.str = NULL;
686
859
        expr->arg_len = 0;
687
860
 
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))
 
889
                                goto out_free_expr;
 
890
                        args++;
 
891
                }
716
892
                else if ((*args)[1] == '-') {
717
893
                        args++;
718
894
                        break;
1140
1316
                                                acl_res |= ACL_PAT_FAIL;
1141
1317
                                }
1142
1318
                                else {
 
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;
 
1325
                                        }
 
1326
 
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)
1147
1330
                                                        break;
 
1331
                                                acl_res |= expr->kw->match(&test, pattern);
1148
1332
                                        }
1149
1333
 
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);
1152
1337
                                }
1153
1338
                                /*
1244
1429
 
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) {
 
1433
                                struct proxy *px;
 
1434
                                struct server *srv;
 
1435
                                char *pname, *sname;
 
1436
 
 
1437
                                if (!expr->arg.str || !*expr->arg.str) {
 
1438
                                        Alert("proxy %s: acl %s %s(): missing server name.\n",
 
1439
                                                p->id, acl->name, expr->kw->kw);
 
1440
                                        cfgerr++;
 
1441
                                        continue;
 
1442
                                }
 
1443
 
 
1444
                                pname = expr->arg.str;
 
1445
                                sname = strrchr(pname, '/');
 
1446
 
 
1447
                                if (sname)
 
1448
                                        *sname++ = '\0';
 
1449
                                else {
 
1450
                                        sname = pname;
 
1451
                                        pname = NULL;
 
1452
                                }
 
1453
 
 
1454
                                px = p;
 
1455
                                if (pname) {
 
1456
                                        px = findproxy(pname, PR_CAP_BE);
 
1457
                                        if (!px) {
 
1458
                                                Alert("proxy %s: acl %s %s(): unable to find proxy '%s'.\n",
 
1459
                                                      p->id, acl->name, expr->kw->kw, pname);
 
1460
                                                cfgerr++;
 
1461
                                                continue;
 
1462
                                        }
 
1463
                                }
 
1464
 
 
1465
                                srv = findserver(px, sname);
 
1466
                                if (!srv) {
 
1467
                                        Alert("proxy %s: acl %s %s(): unable to find server '%s'.\n",
 
1468
                                              p->id, acl->name, expr->kw->kw, sname);
 
1469
                                        cfgerr++;
 
1470
                                        continue;
 
1471
                                }
 
1472
 
 
1473
                                free(expr->arg.str);
 
1474
                                expr->arg_len = 0;
 
1475
                                expr->arg.srv = srv;
 
1476
                                continue;
 
1477
                        }
 
1478
 
1247
1479
                        if (strstr(expr->kw->kw, "http_auth") == expr->kw->kw) {
1248
1480
 
1249
1481
                                if (!expr->arg.str || !*expr->arg.str) {