diff --git a/include/proto/acl.h b/include/proto/acl.h index 3a7606b8e..2c74e2db3 100644 --- a/include/proto/acl.h +++ b/include/proto/acl.h @@ -59,7 +59,7 @@ struct acl_keyword *find_acl_kw(const char *kw); * Right now, the only accepted syntax is : * [...] */ -struct acl_expr *parse_acl_expr(const char **args); +struct acl_expr *parse_acl_expr(const char **args, char **err); /* Purge everything in the acl , then return . */ struct acl *prune_acl(struct acl *acl); @@ -70,7 +70,7 @@ struct acl *prune_acl(struct acl *acl); * * args syntax: */ -struct acl *parse_acl(const char **args, struct list *known_acl); +struct acl *parse_acl(const char **args, struct list *known_acl, char **err); /* Purge everything in the acl_cond , then return . */ struct acl_cond *prune_acl_cond(struct acl_cond *cond); @@ -79,15 +79,16 @@ struct acl_cond *prune_acl_cond(struct acl_cond *cond); * known ACLs passed in . The new condition is returned (or NULL in * case of low memory). Supports multiple conditions separated by "or". */ -struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol); +struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol, char **err); /* Builds an ACL condition starting at the if/unless keyword. The complete * condition is returned. NULL is returned in case of error or if the first * word is neither "if" nor "unless". It automatically sets the file name and * the line number in the condition for better error reporting, and adds the - * ACL requirements to the proxy's acl_requires. + * ACL requirements to the proxy's acl_requires. If is not NULL, it will + * be set to an error message upon errors, that the caller will have to free. */ -struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args); +struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args, char **err); /* Execute condition and return either ACL_PAT_FAIL, ACL_PAT_MISS or * ACL_PAT_PASS depending on the test results. This function only computes the diff --git a/src/acl.c b/src/acl.c index 433a2667e..a040d872b 100644 --- a/src/acl.c +++ b/src/acl.c @@ -1224,11 +1224,14 @@ static int acl_read_patterns_from_file( struct acl_keyword *aclkw, return ret; } -/* Parse an ACL expression starting at [0], and return it. +/* Parse an ACL expression starting at [0], and return it. If is + * not NULL, it will be filled with a pointer to an error message in case of + * error. This pointer must be freeable or NULL. + * * Right now, the only accepted syntax is : * [...] */ -struct acl_expr *parse_acl_expr(const char **args) +struct acl_expr *parse_acl_expr(const char **args, char **err) { __label__ out_return, out_free_expr, out_free_pattern; struct acl_expr *expr; @@ -1238,12 +1241,18 @@ struct acl_expr *parse_acl_expr(const char **args) const char *arg; aclkw = find_acl_kw(args[0]); - if (!aclkw || !aclkw->parse) + if (!aclkw || !aclkw->parse) { + if (err) + memprintf(err, "unknown ACL keyword '%s'", *args); goto out_return; + } expr = (struct acl_expr *)calloc(1, sizeof(*expr)); - if (!expr) + if (!expr) { + if (err) + memprintf(err, "out of memory when parsing ACL expression"); goto out_return; + } expr->kw = aclkw; aclkw->use_cnt++; @@ -1259,8 +1268,11 @@ struct acl_expr *parse_acl_expr(const char **args) /* there are 0 or more arguments in the form "subject(arg[,arg]*)" */ arg++; end = strchr(arg, ')'); - if (!end) + if (!end) { + if (err) + memprintf(err, "missing closing ')' after arguments to ACL keyword '%s'", aclkw->kw); goto out_free_expr; + } /* Parse the arguments. Note that currently we have no way to * report parsing errors, hence the NULL in the error pointers. @@ -1268,12 +1280,22 @@ struct acl_expr *parse_acl_expr(const char **args) * missing. */ nbargs = make_arg_list(arg, end - arg, aclkw->arg_mask, &expr->args, - NULL, NULL, NULL); - if (nbargs < 0) + err, NULL, NULL); + if (nbargs < 0) { + /* note that make_arg_list will have set here */ + if (err) + memprintf(err, "in argument to '%s', %s", aclkw->kw, *err); goto out_free_expr; + } - if (aclkw->val_args && !aclkw->val_args(expr->args, NULL)) - goto out_free_expr; /* invalid keyword argument */ + if (aclkw->val_args && !aclkw->val_args(expr->args, err)) { + /* invalid keyword argument, error must have been + * set by val_args(). + */ + if (err) + memprintf(err, "in argument to '%s', %s", aclkw->kw, *err); + goto out_free_expr; + } } else if (ARGM(aclkw->arg_mask) == 1) { int type = (aclkw->arg_mask >> 4) & 15; @@ -1282,8 +1304,11 @@ struct acl_expr *parse_acl_expr(const char **args) * an empty one so that acl_find_targets() resolves it as * the current one later. */ - if (type != ARGT_FE && type != ARGT_BE && type != ARGT_TAB) + if (type != ARGT_FE && type != ARGT_BE && type != ARGT_TAB) { + if (err) + memprintf(err, "ACL keyword '%s' expects %d arguments", aclkw->kw, ARGM(aclkw->arg_mask)); goto out_free_expr; + } /* Build an arg list containing the type as an empty string * and the usual STOP. @@ -1297,12 +1322,16 @@ struct acl_expr *parse_acl_expr(const char **args) } else if (ARGM(aclkw->arg_mask)) { /* there were some mandatory arguments */ + if (err) + memprintf(err, "ACL keyword '%s' expects %d arguments", aclkw->kw, ARGM(aclkw->arg_mask)); goto out_free_expr; } } else { if (arg) { /* no argument expected */ + if (err) + memprintf(err, "ACL keyword '%s' takes no argument", aclkw->kw); goto out_free_expr; } } @@ -1319,8 +1348,11 @@ struct acl_expr *parse_acl_expr(const char **args) if ((*args)[1] == 'i') patflags |= ACL_PAT_F_IGNORE_CASE; else if ((*args)[1] == 'f') { - if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE)) + if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE)) { + if (err) + memprintf(err, "failed to load some ACL patterns from file '%s'", args[1]); goto out_free_expr; + } args++; } else if ((*args)[1] == '-') { @@ -1337,13 +1369,19 @@ struct acl_expr *parse_acl_expr(const char **args) while (**args) { int ret; pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern)); - if (!pattern) + if (!pattern) { + if (err) + memprintf(err, "out of memory when parsing ACL pattern"); goto out_free_expr; + } pattern->flags = patflags; ret = aclkw->parse(args, pattern, &opaque); - if (!ret) + if (!ret) { + if (err) + memprintf(err, "failed to parse some ACL patterns"); goto out_free_pattern; + } LIST_ADDQ(&expr->patterns, &pattern->list); args += ret; } @@ -1378,23 +1416,31 @@ struct acl *prune_acl(struct acl *acl) { /* Parse an ACL with the name starting at [0], and with a list of already * known ACLs in . If the ACL was not in the list, it will be added. * A pointer to that ACL is returned. If the ACL has an empty name, then it's - * an anonymous one and it won't be merged with any other one. + * an anonymous one and it won't be merged with any other one. If is not + * NULL, it will be filled with an appropriate error. This pointer must be + * freeable or NULL. * * args syntax: */ -struct acl *parse_acl(const char **args, struct list *known_acl) +struct acl *parse_acl(const char **args, struct list *known_acl, char **err) { __label__ out_return, out_free_acl_expr, out_free_name; struct acl *cur_acl; struct acl_expr *acl_expr; char *name; + const char *pos; - if (**args && invalid_char(*args)) + if (**args && (pos = invalid_char(*args))) { + if (err) + memprintf(err, "invalid character in ACL name : '%c'", *pos); goto out_return; + } - acl_expr = parse_acl_expr(args + 1); - if (!acl_expr) + acl_expr = parse_acl_expr(args + 1, err); + if (!acl_expr) { + /* parse_acl_expr will have filled here */ goto out_return; + } /* Check for args beginning with an opening parenthesis just after the * subject, as this is almost certainly a typo. Right now we can only @@ -1415,11 +1461,17 @@ struct acl *parse_acl(const char **args, struct list *known_acl) if (!cur_acl) { name = strdup(args[0]); - if (!name) + if (!name) { + if (err) + memprintf(err, "out of memory when parsing ACL"); goto out_free_acl_expr; + } cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl)); - if (cur_acl == NULL) + if (cur_acl == NULL) { + if (err) + memprintf(err, "out of memory when parsing ACL"); goto out_free_name; + } LIST_INIT(&cur_acl->expr); LIST_ADDQ(known_acl, &cur_acl->list); @@ -1470,9 +1522,11 @@ const struct { /* Find a default ACL from the default_acl list, compile it and return it. * If the ACL is not found, NULL is returned. In theory, it cannot fail, * except when default ACLs are broken, in which case it will return NULL. - * If is not NULL, the ACL will be queued at its tail. + * If is not NULL, the ACL will be queued at its tail. If is + * not NULL, it will be filled with an error message if an error occurs. This + * pointer must be freeable or NULL. */ -struct acl *find_acl_default(const char *acl_name, struct list *known_acl) +struct acl *find_acl_default(const char *acl_name, struct list *known_acl, char **err) { __label__ out_return, out_free_acl_expr, out_free_name; struct acl *cur_acl; @@ -1485,19 +1539,31 @@ struct acl *find_acl_default(const char *acl_name, struct list *known_acl) break; } - if (default_acl_list[index].name == NULL) + if (default_acl_list[index].name == NULL) { + if (err) + memprintf(err, "no such ACL : '%s'", acl_name); return NULL; + } - acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr); - if (!acl_expr) + acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr, err); + if (!acl_expr) { + /* parse_acl_expr must have filled err here */ goto out_return; + } name = strdup(acl_name); - if (!name) + if (!name) { + if (err) + memprintf(err, "out of memory when building default ACL '%s'", acl_name); goto out_free_acl_expr; + } + cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl)); - if (cur_acl == NULL) + if (cur_acl == NULL) { + if (err) + memprintf(err, "out of memory when building default ACL '%s'", acl_name); goto out_free_name; + } cur_acl->name = name; cur_acl->requires |= acl_expr->kw->requires; @@ -1534,9 +1600,12 @@ struct acl_cond *prune_acl_cond(struct acl_cond *cond) /* Parse an ACL condition starting at [0], relying on a list of already * known ACLs passed in . The new condition is returned (or NULL in - * case of low memory). Supports multiple conditions separated by "or". + * case of low memory). Supports multiple conditions separated by "or". If + * is not NULL, it will be filled with a pointer to an error message in + * case of error, that the caller is responsible for freeing. The initial + * location must either be freeable or NULL. */ -struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol) +struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol, char **err) { __label__ out_return, out_free_suite, out_free_term; int arg, neg; @@ -1547,8 +1616,11 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p struct acl_cond *cond; cond = (struct acl_cond *)calloc(1, sizeof(*cond)); - if (cond == NULL) + if (cond == NULL) { + if (err) + memprintf(err, "out of memory when parsing condition"); goto out_return; + } LIST_INIT(&cond->list); LIST_INIT(&cond->suites); @@ -1588,21 +1660,29 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p while (*args[arg_end] && strcmp(args[arg_end], "}") != 0) arg_end++; - if (!*args[arg_end]) + if (!*args[arg_end]) { + if (err) + memprintf(err, "missing closing '}' in condition"); goto out_free_suite; + } args_new = calloc(1, (arg_end - arg + 1) * sizeof(*args_new)); - if (!args_new) + if (!args_new) { + if (err) + memprintf(err, "out of memory when parsing condition"); goto out_free_suite; + } args_new[0] = ""; memcpy(args_new + 1, args + arg + 1, (arg_end - arg) * sizeof(*args_new)); args_new[arg_end - arg] = ""; - cur_acl = parse_acl(args_new, known_acl); + cur_acl = parse_acl(args_new, known_acl, err); free(args_new); - if (!cur_acl) + if (!cur_acl) { + /* note that parse_acl() must have filled here */ goto out_free_suite; + } arg = arg_end; } else { @@ -1613,15 +1693,20 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p */ cur_acl = find_acl_by_name(word, known_acl); if (cur_acl == NULL) { - cur_acl = find_acl_default(word, known_acl); - if (cur_acl == NULL) + cur_acl = find_acl_default(word, known_acl, err); + if (cur_acl == NULL) { + /* note that find_acl_default() must have filled here */ goto out_free_suite; + } } } cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term)); - if (cur_term == NULL) + if (cur_term == NULL) { + if (err) + memprintf(err, "out of memory when parsing condition"); goto out_free_suite; + } cur_term->acl = cur_acl; cur_term->neg = neg; @@ -1629,8 +1714,11 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p if (!cur_suite) { cur_suite = (struct acl_term_suite *)calloc(1, sizeof(*cur_suite)); - if (cur_term == NULL) + if (cur_term == NULL) { + if (err) + memprintf(err, "out of memory when parsing condition"); goto out_free_term; + } LIST_INIT(&cur_suite->terms); LIST_ADDQ(&cond->suites, &cur_suite->list); } @@ -1653,13 +1741,19 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p * condition is returned. NULL is returned in case of error or if the first * word is neither "if" nor "unless". It automatically sets the file name and * the line number in the condition for better error reporting, and adds the - * ACL requirements to the proxy's acl_requires. + * ACL requirements to the proxy's acl_requires. If is not NULL, it will + * be filled with a pointer to an error message in case of error, that the + * caller is responsible for freeing. The initial location must either be + * freeable or NULL. */ -struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args) +struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args, char **err) { int pol = ACL_COND_NONE; struct acl_cond *cond = NULL; + if (err) + *err = NULL; + if (!strcmp(*args, "if")) { pol = ACL_COND_IF; args++; @@ -1668,12 +1762,17 @@ struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, co pol = ACL_COND_UNLESS; args++; } - else + else { + if (err) + memprintf(err, "conditions must start with either 'if' or 'unless'"); return NULL; + } - cond = parse_acl_cond(args, &px->acl, pol); - if (!cond) + cond = parse_acl_cond(args, &px->acl, pol, err); + if (!cond) { + /* note that parse_acl_cond must have filled here */ return NULL; + } cond->file = file; cond->line = line; diff --git a/src/cfgparse.c b/src/cfgparse.c index a3ac66121..8b5eae312 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1085,6 +1085,7 @@ static int create_cond_regex_rule(const char *file, int line, const char **cond_start) { regex_t *preg = NULL; + char *errmsg = NULL; const char *err; int err_code = 0; struct acl_cond *cond = NULL; @@ -1106,9 +1107,10 @@ static int create_cond_regex_rule(const char *file, int line, if (cond_start && (strcmp(*cond_start, "if") == 0 || strcmp(*cond_start, "unless") == 0)) { - if ((cond = build_acl_cond(file, line, px, cond_start)) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n", - file, line, cmd); + if ((cond = build_acl_cond(file, line, px, cond_start, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n", + file, line, cmd, errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto err; } @@ -2073,6 +2075,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) curproxy->bind_proc = set; } else if (!strcmp(args[0], "acl")) { /* add an ACL */ + char *errmsg = NULL; + if (curproxy == &defproxy) { Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); err_code |= ERR_ALERT | ERR_FATAL; @@ -2086,9 +2090,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) err_code |= ERR_ALERT | ERR_FATAL; } - if (parse_acl((const char **)args + 1, &curproxy->acl) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing ACL '%s'.\n", - file, linenum, args[1]); + if (parse_acl((const char **)args + 1, &curproxy->acl, &errmsg) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing ACL '%s' : %s.\n", + file, linenum, args[1], errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -2507,6 +2512,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) curproxy->server_id_hdr_len = strlen(curproxy->server_id_hdr_name); } else if (!strcmp(args[0], "block")) { /* early blocking based on ACLs */ + char *errmsg = NULL; + if (curproxy == &defproxy) { Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); err_code |= ERR_ALERT | ERR_FATAL; @@ -2520,9 +2527,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) goto out; } - if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1)) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing blocking condition.\n", - file, linenum); + if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing blocking condition : %s.\n", + file, linenum, errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -2620,10 +2628,13 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } else if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) { - cond = build_acl_cond(file, linenum, curproxy, (const char **)args + cur_arg); + char *errmsg = NULL; + + cond = build_acl_cond(file, linenum, curproxy, (const char **)args + cur_arg, &errmsg); if (!cond) { - Alert("parsing [%s:%d] : '%s': error detected while parsing redirect condition.\n", - file, linenum, args[0]); + Alert("parsing [%s:%d] : '%s': error detected while parsing redirect condition : %s.\n", + file, linenum, args[0], errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -2676,6 +2687,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } else if (!strcmp(args[0], "use_backend")) { struct switching_rule *rule; + char *errmsg = NULL; if (curproxy == &defproxy) { Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); @@ -2699,9 +2711,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) goto out; } - if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing switching rule.\n", - file, linenum); + if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n", + file, linenum, errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -2716,6 +2729,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } else if (strcmp(args[0], "use-server") == 0) { struct server_rule *rule; + char *errmsg = NULL; if (curproxy == &defproxy) { Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); @@ -2739,9 +2753,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) goto out; } - if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing switching rule.\n", - file, linenum); + if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n", + file, linenum, errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -2758,6 +2773,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) else if ((!strcmp(args[0], "force-persist")) || (!strcmp(args[0], "ignore-persist"))) { struct persist_rule *rule; + char *errmsg = NULL; if (curproxy == &defproxy) { Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); @@ -2775,9 +2791,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) goto out; } - if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1)) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing a '%s' rule.\n", - file, linenum, args[0]); + if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing a '%s' rule : %s.\n", + file, linenum, args[0], errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -2953,6 +2970,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) struct sticking_rule *rule; struct pattern_expr *expr; int myidx = 0; + char *errmsg = NULL; const char *name = NULL; int flags; @@ -3028,9 +3046,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) { - if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + myidx)) == NULL) { - Alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition.\n", - file, linenum, args[0]); + if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + myidx, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition : %s.\n", + file, linenum, args[0], errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; free(expr); goto out; @@ -3070,6 +3089,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) goto stats_error_parsing; } else if (!strcmp(args[1], "admin")) { struct stats_admin_rule *rule; + char *errmsg = NULL; if (curproxy == &defproxy) { Alert("parsing [%s:%d]: '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]); @@ -3089,9 +3109,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) err_code |= ERR_ALERT | ERR_FATAL; goto out; } - if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule.\n", - file, linenum, args[0], args[1]); + if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule : %s.\n", + file, linenum, args[0], args[1], errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -3846,6 +3867,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) err_code |= ERR_WARN; if (strcmp(args[1], "fail") == 0) { + char *errmsg = NULL; + /* add a condition to fail monitor requests */ if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) { Alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n", @@ -3854,9 +3877,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) goto out; } - if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition.\n", - file, linenum, args[0], args[1]); + if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n", + file, linenum, args[0], args[1], errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -4987,6 +5011,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } else if (!strcmp(args[0], "reqadd")) { /* add request header */ struct cond_wordlist *wl; + char *errmsg = NULL; if (curproxy == &defproxy) { Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); @@ -5003,9 +5028,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) { - if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2)) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n", - file, linenum, args[0]); + if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n", + file, linenum, args[0], errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -5082,6 +5108,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } else if (!strcmp(args[0], "rspadd")) { /* add response header */ struct cond_wordlist *wl; + char *errmsg = NULL; if (curproxy == &defproxy) { Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); @@ -5098,9 +5125,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) { - if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2)) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n", - file, linenum, args[0]); + if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n", + file, linenum, args[0], errmsg); + free(errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } diff --git a/src/proto_http.c b/src/proto_http.c index a173f8861..07e0eb597 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -7506,10 +7506,12 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) { struct acl_cond *cond; + char *errmsg = NULL; - if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg)) == NULL) { - Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition.\n", - file, linenum, args[0]); + if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition : %s.\n", + file, linenum, args[0], errmsg); + free(errmsg); return NULL; } rule->cond = cond; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 4aa47293f..dc7812d21 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -962,10 +962,13 @@ static int tcp_parse_response_rule(char **args, int arg, int section_type, } if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) { - if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) { + char *errmsg = NULL; + + if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, &errmsg)) == NULL) { snprintf(err, errlen, - "error detected in %s '%s' while parsing '%s' condition", - proxy_type_str(curpx), curpx->id, args[arg]); + "error detected in %s '%s' while parsing '%s' condition : %s", + proxy_type_str(curpx), curpx->id, args[arg], errmsg); + free(errmsg); return -1; } } @@ -1032,10 +1035,13 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type, } if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) { - if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) { + char *errmsg = NULL; + + if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, &errmsg)) == NULL) { snprintf(err, errlen, - "error detected in %s '%s' while parsing '%s' condition", - proxy_type_str(curpx), curpx->id, args[arg]); + "error detected in %s '%s' while parsing '%s' condition : %s", + proxy_type_str(curpx), curpx->id, args[arg], errmsg); + free(errmsg); return -1; } }