MAJOR: acl: ensure that implicit table and proxies are valid

A large number of ACLs make use of frontend, backend or table names in their
arguments, and fall back to the current proxy when no argument is passed. If
the expected capability is not available, the ACL silently fails at runtime.

Now we make all those names mandatory in the parser and we rely on
acl_find_targets() to replace the missing names with the holding proxy,
then to perform the appropriate tests, and to reject errors at parsing
time.

It is possible that some faulty configurations will get rejected from now
on, while they used to silently fail till now. This is the reason why this
change is marked as MAJOR.
diff --git a/src/acl.c b/src/acl.c
index dc9925d..025e478 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -1396,6 +1396,26 @@
 			if (nbargs < 0)
 				goto out_free_expr;
 		}
+		else if (ARGM(aclkw->arg_mask) == 1) {
+			int type = (aclkw->arg_mask >> 4) & 15;
+
+			/* If a proxy is noted as a mandatory argument, we'll fake
+			 * 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)
+				goto out_free_expr;
+
+			/* Build an arg list containing the type as an empty string
+			 * and the usual STOP.
+			 */
+			expr->args = calloc(2, sizeof(*expr->args));
+			expr->args[0].type = type;
+			expr->args[0].data.str.str = strdup("");
+			expr->args[0].data.str.len = 1;
+			expr->args[0].data.str.len = 0;
+			expr->args[1].type = ARGT_STOP;
+		}
 		else if (ARGM(aclkw->arg_mask)) {
 			/* there were some mandatory arguments */
 			goto out_free_expr;
@@ -2013,18 +2033,14 @@
 					expr->args->data.srv = srv;
 				}
 				else if (arg->type == ARGT_FE) {
-					struct proxy *prx;
-					char *pname;
+					struct proxy *prx = p;
+					char *pname = p->id;
 
-					if (!expr->args->data.str.len) {
-						Alert("proxy %s: acl '%s' %s(): missing frontend name.\n",
-						      p->id, acl->name, expr->kw->kw);
-						cfgerr++;
-						continue;
+					if (expr->args->data.str.len) {
+						pname = expr->args->data.str.str;
+						prx = findproxy(pname, PR_CAP_FE);
 					}
 
-					pname = expr->args->data.str.str;
-					prx = findproxy(pname, PR_CAP_FE);
 					if (!prx) {
 						Alert("proxy %s: acl '%s' %s(): unable to find frontend '%s'.\n",
 						      p->id, acl->name, expr->kw->kw, pname);
@@ -2032,22 +2048,25 @@
 						continue;
 					}
 
+					if (!(prx->cap & PR_CAP_FE)) {
+						Alert("proxy %s: acl '%s' %s(): proxy '%s' has no frontend capability.\n",
+						      p->id, acl->name, expr->kw->kw, pname);
+						cfgerr++;
+						continue;
+					}
+
 					free(expr->args->data.str.str);
 					expr->args->data.prx = prx;
 				}
 				else if (arg->type == ARGT_BE) {
-					struct proxy *prx;
-					char *pname;
+					struct proxy *prx = p;
+					char *pname = p->id;
 
-					if (!expr->args->data.str.len) {
-						Alert("proxy %s: acl '%s' %s(): missing backend name.\n",
-						      p->id, acl->name, expr->kw->kw);
-						cfgerr++;
-						continue;
+					if (expr->args->data.str.len) {
+						pname = expr->args->data.str.str;
+						prx = findproxy(pname, PR_CAP_BE);
 					}
 
-					pname = expr->args->data.str.str;
-					prx = findproxy(pname, PR_CAP_BE);
 					if (!prx) {
 						Alert("proxy %s: acl '%s' %s(): unable to find backend '%s'.\n",
 						      p->id, acl->name, expr->kw->kw, pname);
@@ -2055,22 +2074,25 @@
 						continue;
 					}
 
+					if (!(prx->cap & PR_CAP_BE)) {
+						Alert("proxy %s: acl '%s' %s(): proxy '%s' has no backend capability.\n",
+						      p->id, acl->name, expr->kw->kw, pname);
+						cfgerr++;
+						continue;
+					}
+
 					free(expr->args->data.str.str);
 					expr->args->data.prx = prx;
 				}
 				else if (arg->type == ARGT_TAB) {
-					struct proxy *prx;
-					char *pname;
+					struct proxy *prx = p;
+					char *pname = p->id;
 
-					if (!expr->args->data.str.len) {
-						Alert("proxy %s: acl '%s' %s(): missing table name.\n",
-						      p->id, acl->name, expr->kw->kw);
-						cfgerr++;
-						continue;
+					if (expr->args->data.str.len) {
+						pname = expr->args->data.str.str;
+						prx = find_stktable(pname);
 					}
 
-					pname = expr->args->data.str.str;
-					prx = find_stktable(pname);
 					if (!prx) {
 						Alert("proxy %s: acl '%s' %s(): unable to find table '%s'.\n",
 						      p->id, acl->name, expr->kw->kw, pname);
@@ -2078,6 +2100,14 @@
 						continue;
 					}
 
+
+					if (!prx->table.size) {
+						Alert("proxy %s: acl '%s' %s(): no table in proxy '%s'.\n",
+						      p->id, acl->name, expr->kw->kw, pname);
+						cfgerr++;
+						continue;
+					}
+
 					free(expr->args->data.str.str);
 					expr->args->data.prx = prx;
 				}