[MEDIUM] acl: support '-i' to ignore case when matching
Implemented the "-i" option on ACLs to state that the matching will have to be performed for all patterns ignoring case. The usage is : acl <aclname> <aclsubject> -i pattern1 ... If a pattern must begin with "-", either it must not be the first one, or the "--" option should be specified first.
This commit is contained in:
parent
0fc45a7e83
commit
c8d7c96b26
|
@ -67,6 +67,12 @@ enum {
|
|||
ACL_DIR_RTR, /* ACL evaluated on response */
|
||||
};
|
||||
|
||||
/* possible flags for expressions or patterns */
|
||||
enum {
|
||||
ACL_PAT_F_IGNORE_CASE = 1 << 0, /* ignore case */
|
||||
ACL_PAT_F_FROM_FILE = 1 << 1, /* pattern comes from a file */
|
||||
};
|
||||
|
||||
/* How to store a time range and the valid days in 29 bits */
|
||||
struct acl_time {
|
||||
int dow:7; /* 1 bit per day of week: 0-6 */
|
||||
|
@ -96,6 +102,7 @@ struct acl_pattern {
|
|||
regex_t *reg; /* a compiled regex */
|
||||
} ptr; /* indirect values, allocated */
|
||||
int len; /* data length when required */
|
||||
int flags; /* expr or pattern flags. */
|
||||
};
|
||||
|
||||
/* The structure exchanged between an acl_fetch_* function responsible for
|
||||
|
|
101
src/acl.c
101
src/acl.c
|
@ -41,9 +41,14 @@ int acl_match_pst(struct acl_test *test, struct acl_pattern *pattern)
|
|||
/* NB: For two strings to be identical, it is required that their lengths match */
|
||||
int acl_match_str(struct acl_test *test, struct acl_pattern *pattern)
|
||||
{
|
||||
int icase;
|
||||
|
||||
if (pattern->len != test->len)
|
||||
return 0;
|
||||
if (strncmp(pattern->ptr.str, test->ptr, test->len) == 0)
|
||||
|
||||
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
|
||||
if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) == 0) ||
|
||||
(!icase && strncmp(pattern->ptr.str, test->ptr, test->len) == 0))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -89,9 +94,14 @@ int acl_match_reg(struct acl_test *test, struct acl_pattern *pattern)
|
|||
/* Checks that the pattern matches the beginning of the tested string. */
|
||||
int acl_match_beg(struct acl_test *test, struct acl_pattern *pattern)
|
||||
{
|
||||
int icase;
|
||||
|
||||
if (pattern->len > test->len)
|
||||
return 0;
|
||||
if (strncmp(pattern->ptr.str, test->ptr, pattern->len) != 0)
|
||||
|
||||
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
|
||||
if ((icase && strncasecmp(pattern->ptr.str, test->ptr, pattern->len) != 0) ||
|
||||
(!icase && strncmp(pattern->ptr.str, test->ptr, pattern->len) != 0))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -99,9 +109,13 @@ int acl_match_beg(struct acl_test *test, struct acl_pattern *pattern)
|
|||
/* Checks that the pattern matches the end of the tested string. */
|
||||
int acl_match_end(struct acl_test *test, struct acl_pattern *pattern)
|
||||
{
|
||||
int icase;
|
||||
|
||||
if (pattern->len > test->len)
|
||||
return 0;
|
||||
if (strncmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0)
|
||||
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
|
||||
if ((icase && strncasecmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0) ||
|
||||
(!icase && strncmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -111,6 +125,7 @@ int acl_match_end(struct acl_test *test, struct acl_pattern *pattern)
|
|||
*/
|
||||
int acl_match_sub(struct acl_test *test, struct acl_pattern *pattern)
|
||||
{
|
||||
int icase;
|
||||
char *end;
|
||||
char *c;
|
||||
|
||||
|
@ -118,11 +133,21 @@ int acl_match_sub(struct acl_test *test, struct acl_pattern *pattern)
|
|||
return 0;
|
||||
|
||||
end = test->ptr + test->len - pattern->len;
|
||||
for (c = test->ptr; c <= end; c++) {
|
||||
if (*c != *pattern->ptr.str)
|
||||
continue;
|
||||
if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
|
||||
return 1;
|
||||
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
|
||||
if (icase) {
|
||||
for (c = test->ptr; c <= end; c++) {
|
||||
if (tolower(*c) != tolower(*pattern->ptr.str))
|
||||
continue;
|
||||
if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
for (c = test->ptr; c <= end; c++) {
|
||||
if (*c != *pattern->ptr.str)
|
||||
continue;
|
||||
if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -130,41 +155,52 @@ int acl_match_sub(struct acl_test *test, struct acl_pattern *pattern)
|
|||
/* This one is used by other real functions. It checks that the pattern is
|
||||
* included inside the tested string, but enclosed between the specified
|
||||
* delimitor, or a '/' or a '?' or at the beginning or end of the string.
|
||||
* The delimitor is stripped at the beginning or end of the pattern are
|
||||
* ignored.
|
||||
* The delimitor is stripped at the beginning or end of the pattern.
|
||||
*/
|
||||
static int match_word(struct acl_test *test, struct acl_pattern *pattern, char delim)
|
||||
{
|
||||
int may_match;
|
||||
int may_match, icase;
|
||||
char *c, *end;
|
||||
char *ps;
|
||||
int pl;
|
||||
|
||||
pl = pattern->len;
|
||||
ps = pattern->ptr.str;
|
||||
while (pl > 0 && *ps == delim) {
|
||||
while (pl > 0 && (*ps == delim || *ps == '/' || *ps == '?')) {
|
||||
pl--;
|
||||
ps++;
|
||||
}
|
||||
|
||||
while (pl > 0 && *(ps + pl - 1) == delim)
|
||||
while (pl > 0 &&
|
||||
(ps[pl - 1] == delim || ps[pl - 1] == '/' || ps[pl - 1] == '?'))
|
||||
pl--;
|
||||
|
||||
if (pl > test->len)
|
||||
return 0;
|
||||
|
||||
may_match = 1;
|
||||
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
|
||||
end = test->ptr + test->len - pl;
|
||||
for (c = test->ptr; c <= end; c++) {
|
||||
if (*c == '/' || *c == delim || *c == '?') {
|
||||
may_match = 1;
|
||||
continue;
|
||||
}
|
||||
if (may_match && (*c == *ps) &&
|
||||
(strncmp(ps, c, pl) == 0) &&
|
||||
(c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
|
||||
return 1;
|
||||
|
||||
if (!may_match)
|
||||
continue;
|
||||
|
||||
if (icase) {
|
||||
if ((tolower(*c) == tolower(*ps)) &&
|
||||
(strncasecmp(ps, c, pl) == 0) &&
|
||||
(c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
|
||||
return 1;
|
||||
} else {
|
||||
if ((*c == *ps) &&
|
||||
(strncmp(ps, c, pl) == 0) &&
|
||||
(c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
|
||||
return 1;
|
||||
}
|
||||
may_match = 0;
|
||||
}
|
||||
return 0;
|
||||
|
@ -227,13 +263,15 @@ int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque)
|
|||
int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque)
|
||||
{
|
||||
regex_t *preg;
|
||||
int icase;
|
||||
|
||||
preg = calloc(1, sizeof(regex_t));
|
||||
|
||||
if (!preg)
|
||||
return 0;
|
||||
|
||||
if (regcomp(preg, *text, REG_EXTENDED | REG_NOSUB) != 0) {
|
||||
icase = (pattern->flags & ACL_PAT_F_IGNORE_CASE) ? REG_ICASE : 0;
|
||||
if (regcomp(preg, *text, REG_EXTENDED | REG_NOSUB | icase) != 0) {
|
||||
free(preg);
|
||||
return 0;
|
||||
}
|
||||
|
@ -420,7 +458,7 @@ struct acl_expr *parse_acl_expr(const char **args)
|
|||
struct acl_expr *expr;
|
||||
struct acl_keyword *aclkw;
|
||||
struct acl_pattern *pattern;
|
||||
int opaque;
|
||||
int opaque, patflags;
|
||||
const char *arg;
|
||||
|
||||
aclkw = find_acl_kw(args[0]);
|
||||
|
@ -454,14 +492,37 @@ struct acl_expr *parse_acl_expr(const char **args)
|
|||
expr->arg.str = arg2;
|
||||
}
|
||||
|
||||
/* now parse all patterns */
|
||||
args++;
|
||||
|
||||
/* check for options before patterns. Supported options are :
|
||||
* -i : ignore case for all patterns by default
|
||||
* -f : read patterns from those files
|
||||
* -- : everything after this is not an option
|
||||
*/
|
||||
patflags = 0;
|
||||
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] == '-') {
|
||||
args++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
args++;
|
||||
}
|
||||
|
||||
/* now parse all patterns */
|
||||
opaque = 0;
|
||||
while (**args) {
|
||||
int ret;
|
||||
pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
|
||||
if (!pattern)
|
||||
goto out_free_expr;
|
||||
pattern->flags = patflags;
|
||||
|
||||
ret = aclkw->parse(args, pattern, &opaque);
|
||||
if (!ret)
|
||||
goto out_free_pattern;
|
||||
|
|
|
@ -5283,6 +5283,8 @@ acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
|
|||
|
||||
static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
|
||||
{
|
||||
int icase;
|
||||
|
||||
if (test->i != pattern->val.i)
|
||||
return 0;
|
||||
|
||||
|
@ -5292,7 +5294,10 @@ static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
|
|||
/* Other method, we must compare the strings */
|
||||
if (pattern->len != test->len)
|
||||
return 0;
|
||||
if (strncmp(pattern->ptr.str, test->ptr, test->len) != 0)
|
||||
|
||||
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
|
||||
if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
|
||||
(!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue