From: Kirill A. Korinsky Subject: Re: smtpd: allow braces for `listen' options To: Omar Polo Cc: tech@openbsd.org Date: Mon, 21 Oct 2024 20:17:41 +0200 On Mon, 21 Oct 2024 19:03:22 +0200, Omar Polo wrote: > > unfortunately not. shift-reduce (or reduce-reduce) conflicts are due to > an ambiguous grammar. I'm trying to keep smtpd' grammar non ambiguous, > since that has also other interesting properties :-) > > The issue here is at a lower level. The lexer will, say, emit a token > LISTEN whenever it sees "listen" in the input file, regardless of where > we are in the config. Then, we require { ... } to have only STRING > inside, but the parser doesn't know it, and yacc reports a syntax error > since it has found a, say, LISTEN token instead of a STRING one. > > (and afaik we don't have a way to tell yacc to accept any token in a > grammar rule) > > I was wandering about adding a flag to control the lexer, but it's too > fragile and also a bit ugly. Luckily, I think this in practice will not > occur often, and quoting of reserved keywords is already required. So, > I believe that your idea of parsing "-foo" as a string instead of > erroring could actually work out. I still have to study the > implications of doing so however. (ENOTENOUGHTIME unfortunately :-/) ah, when here a bit ugly way which allows me to parse a block like this: filter dnsbl proc-exec { /tmp/filter-dnsbl -m action ca 123 -123 domain3 domain4 } and execute /tmp/filter-dnsbl with args: -m action ca 123 -123 domain3 domain4 here an updated diff: Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v diff -u -p -r1.299 parse.y --- parse.y 19 Feb 2024 21:00:19 -0000 1.299 +++ parse.y 21 Oct 2024 18:16:15 -0000 @@ -162,6 +162,8 @@ typedef struct { int lineno; } YYSTYPE; +static int lookup_as_string; + %} %token ACTION ADMD ALIAS ANY ARROW AUTH AUTH_OPTIONAL @@ -191,6 +193,7 @@ typedef struct { %token STRING %token NUMBER %type table +%type numberstr cmdline cmdline_l %type size negation %type tables tablenew tableref %% @@ -295,6 +298,34 @@ tableval_list : string_list { } | keyval_list { } ; +numberstr: +STRING +| NUMBER { + if (asprintf(&$$, "%lld", (long long)$1) == -1) + fatalx("asprintf"); +} +; + +cmdline_l: +numberstr optnl { $$ = $1; } +| cmdline_l numberstr optnl { + if (asprintf(&$$, "%s %s", $1, $2) == -1) + fatalx("asprint"); + free($1); + free($2); +} +; + +cmdline: +STRING +| '{' optnl { + lookup_as_string = 1; +} cmdline_l '}' { + lookup_as_string = 0; + $$ = $4; + } +; + bounce: BOUNCE WARN_INTERVAL { memset(conf->sc_bounce_warn, 0, sizeof conf->sc_bounce_warn); @@ -1911,7 +1942,7 @@ FILTER STRING PROC STRING { filter_config = NULL; } | -FILTER STRING PROC_EXEC STRING { +FILTER STRING PROC_EXEC cmdline { if (dict_get(conf->sc_filters_dict, $2)) { yyerror("filter already exists with that name: %s", $2); free($2); @@ -2752,7 +2783,7 @@ lookup(char *s) p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); - if (p) + if (p && !lookup_as_string) return (p->k_val); else return (STRING); @@ -2889,7 +2920,7 @@ top: yyerror("string too long"); return (findeol()); } - if (isalnum(c) || c == '_') { + if (isalnum(c) || c == '/' || c == '-' || c == '_') { *p++ = c; continue; } @@ -2983,8 +3014,6 @@ nodigits: while (p > buf + 1) lungetc((unsigned char)*--p); c = (unsigned char)*--p; - if (c == '-') - return (c); } } @@ -3001,7 +3030,7 @@ nodigits: x != '!' && x != '=' && x != '#' && \ x != ',')) - if (isalnum(c) || c == ':' || c == '_') { + if (isalnum(c) || c == ':' || c == '/' || c == '-' || c == '_') { do { *p++ = c; if ((size_t)(p-buf) >= sizeof(buf)) { -- wbr, Kirill