[MINOR] acl: support loading values from files
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.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 47e4ed4..1ca54fe 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -5886,9 +5886,27 @@
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
diff --git a/src/acl.c b/src/acl.c
index be752b0..a4ea068 100644
--- 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 @@
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 @@
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;