]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] acl: support loading values from files
authorWilly Tarreau <w@1wt.eu>
Sun, 9 May 2010 21:45:24 +0000 (23:45 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 9 May 2010 21:45:24 +0000 (23:45 +0200)
The "acl XXX -f <file>" syntax was supported but nothing was read from
the file. This is now possible. All lines are merged verbatim, even if
they contain spaces (useful for user-agents). There are shortcomings
though. The worst one is that error reporting is too approximative.

doc/configuration.txt
src/acl.c

index 47e4ed4060138b6f737fbd1f9fd96e62be93806f..1ca54fe80948d790ee2a99934dfc96399a2c9cc7 100644 (file)
@@ -5886,9 +5886,27 @@ performance, they just consume a small amount of memory.
 
 The following ACL flags are currently supported :
 
-   -i : ignore case during matching.
+   -i : ignore case during matching of all subsequent patterns.
+   -f : load patterns from a file.
    -- : force end of flags. Useful when a string looks like one of the flags.
 
+The "-f" flag is special as it loads all of the lines it finds in the file
+specified in argument and loads all of them before continuing. It is even
+possible to pass multiple "-f" arguments if the patterns are to be loaded from
+multiple files. Also, note that the "-i" flag applies to subsequent entries and
+not to entries loaded from files preceeding it. For instance :
+
+    acl valid-ua hdr(user-agent) -f exact-ua.lst -i -f generic-ua.lst  test
+
+In this example, each line of "exact-ua.lst" will be exactly matched against
+the "user-agent" header of the request. Then each line of "generic-ua" will be
+case-insensitively matched. Then the word "test" will be insensitively matched
+too.
+
+Note that right now it is difficult for the ACL parsers to report errors, so if
+a file is unreadable or unparsable, the most you'll get is a parse error in the
+ACL. Thus, file-based ACLs should only be produced by reliable processes.
+
 Supported types of values are :
 
   - integers or integer ranges
index be752b069feb18aa3b549729e7ef2c2eacb75a87..a4ea068f6cf33ad07c2bef4872ff58bd3d0982e4 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -19,6 +19,8 @@
 #include <common/standard.h>
 #include <common/uri_auth.h>
 
+#include <types/global.h>
+
 #include <proto/acl.h>
 #include <proto/auth.h>
 #include <proto/log.h>
@@ -658,6 +660,52 @@ static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
        return expr;
 }
 
+static int acl_read_patterns_from_file(        struct acl_keyword *aclkw,
+                                       struct acl_expr *expr,
+                                       const char *filename, int patflags)
+{
+       FILE *file;
+       char *c;
+       const char *args[2];
+       struct acl_pattern *pattern;
+       int opaque;
+
+       file = fopen(filename, "r");
+       if (!file)
+               return 0;
+
+       /* now parse all patterns. The file may contain only one pattern per
+        * line. If the line contains spaces, they will be part of the pattern.
+        * The pattern stops at the first CR, LF or EOF encountered.
+        */
+       opaque = 0;
+       args[0] = trash;
+       args[1] = "";
+       while (fgets(trash, sizeof(trash), file) != NULL) {
+
+               c = trash;
+               while (*c && *c != '\n' && *c != '\r')
+                       c++;
+               *c = 0;
+
+               pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
+               if (!pattern)
+                       goto out_close;
+               pattern->flags = patflags;
+
+               if (!aclkw->parse(args, pattern, &opaque))
+                       goto out_free_pattern;
+               LIST_ADDQ(&expr->patterns, &pattern->list);
+       }
+       return 1;
+
+ out_free_pattern:
+       free_pattern(pattern);
+ out_close:
+       fclose(file);
+       return 0;
+}
+
 /* Parse an ACL expression starting at <args>[0], and return it.
  * Right now, the only accepted syntax is :
  * <subject> [<value>...]
@@ -711,8 +759,11 @@ struct acl_expr *parse_acl_expr(const char **args)
        while (**args == '-') {
                if ((*args)[1] == 'i')
                        patflags |= ACL_PAT_F_IGNORE_CASE;
-               else if ((*args)[1] == 'f')
-                       patflags |= ACL_PAT_F_FROM_FILE;
+               else if ((*args)[1] == 'f') {
+                       if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE))
+                               goto out_free_expr;
+                       args++;
+               }
                else if ((*args)[1] == '-') {
                        args++;
                        break;