123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- /*
- * Copyright (c) 2019 Markus Hennecke. All rights reserved.
- * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
- * Copyright (c) 2001 Markus Friedl. All rights reserved.
- * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
- * Copyright (c) 2001 Theo de Raadt. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- %{
- #include <ctype.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <limits.h>
- #include "dnsbl.h"
- #include "log.h"
- int yyerror(const char *, ...);
- int yylex(void);
- int lookup(char *);
- int kw_cmp(const void *, const void *);
- int lgetc(int);
- int lungetc(int);
- int findeol(void);
- FILE *file;
- int lineno;
- struct config *cfg;
- typedef struct {
- char *string;
- int lineno;
- } YYSTYPE;
- %}
- %token SET AUTOWHITELIST OFF ON
- %token LIST HAS DNS
- %token SPAMD LOGFILE IS STRING
- %token ERROR
- %token <string> STRING
- %%
- grammar : /* empty */
- | grammar '\n'
- | grammar setting '\n'
- | grammar dnsbl '\n'
- | grammar logfile '\n'
- ;
- logfile : SPAMD LOGFILE IS STRING {
- if (cfg->logfile) {
- yyerror("multiple \"logfile\" entries");
- } else {
- cfg->logfile = strdup($4);
- }
- if (cfg->logfile == NULL)
- fatal(NULL);
- }
- ;
- dnsbl : LIST STRING HAS DNS STRING {
- config_add_spamlist(cfg, $2, $5);
- }
- ;
- setting : SET AUTOWHITELIST OFF {
- cfg->autowhitelist = 0;
- }
- | SET AUTOWHITELIST ON {
- cfg->autowhitelist = 1;
- }
- ;
- %%
- int
- yyerror(const char *fmt, ...)
- {
- va_list ap;
- char *msg;
- va_start(ap, fmt);
- if (vasprintf(&msg, fmt, ap) == -1)
- fatalx("yyerror vasprintf");
- va_end(ap);
- log_warnx("ERROR: %s in line %d", msg, lineno);
- return 0;
- }
- struct keywords {
- const char *k_name;
- int k_val;
- };
- int
- kw_cmp(const void *k, const void *e)
- {
- return (strcmp(k, ((const struct keywords *)e)->k_name));
- }
- int
- lookup(char *s)
- {
- /* must be sorted */
- static const struct keywords keywords[] = {
- { "autowhitelist", AUTOWHITELIST },
- { "dns", DNS },
- { "has", HAS },
- { "is", IS },
- { "list", LIST },
- { "logfile", LOGFILE },
- { "off", OFF },
- { "on", ON },
- { "set", SET },
- { "spamd", SPAMD },
- };
- const struct keywords *p;
- p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
- sizeof(keywords[0]), kw_cmp);
- if (p)
- return (p->k_val);
- else
- return (STRING);
- }
- #define MAXPUSHBACK 128
- u_char *parsebuf;
- int parseindex;
- u_char pushback_buffer[MAXPUSHBACK];
- int pushback_index = 0;
- int
- lgetc(int quotec)
- {
- int c, next;
- if (parsebuf) {
- /* Read character from the parsebuffer instead of input. */
- if (parseindex >= 0) {
- c = parsebuf[parseindex++];
- if (c != '\0')
- return (c);
- parsebuf = NULL;
- } else
- parseindex++;
- }
- if (pushback_index)
- return (pushback_buffer[--pushback_index]);
- if (quotec) {
- if ((c = getc(file)) == EOF) {
- yyerror("reached end of file while parsing "
- "quoted string");
- return (EOF);
- }
- return (c);
- }
- while ((c = getc(file)) == '\\') {
- next = getc(file);
- if (next != '\n') {
- c = next;
- break;
- }
- yylval.lineno = lineno;
- lineno++;
- }
- return (c);
- }
- int
- lungetc(int c)
- {
- if (c == EOF)
- return (EOF);
- if (parsebuf) {
- parseindex--;
- if (parseindex >= 0)
- return (c);
- }
- if (pushback_index < MAXPUSHBACK-1)
- return (pushback_buffer[pushback_index++] = c);
- else
- return (EOF);
- }
- int
- findeol(void)
- {
- int c;
- parsebuf = NULL;
- /* skip to either EOF or the first real EOL */
- while (1) {
- if (pushback_index)
- c = pushback_buffer[--pushback_index];
- else
- c = lgetc(0);
- if (c == '\n') {
- lineno++;
- break;
- }
- if (c == EOF)
- break;
- }
- return (ERROR);
- }
- int
- yylex(void)
- {
- u_char buf[8096];
- u_char *p;
- int quotec, next, c;
- int token;
- p = buf;
- while ((c = lgetc(0)) == ' ' || c == '\t')
- ; /* nothing */
- yylval.lineno = lineno;
- if (c == '#')
- while ((c = lgetc(0)) != '\n' && c != EOF)
- ; /* nothing */
- switch (c) {
- case '\'':
- case '"':
- quotec = c;
- while (1) {
- if ((c = lgetc(quotec)) == EOF)
- return (0);
- if (c == '\n') {
- lineno++;
- continue;
- } else if (c == '\\') {
- if ((next = lgetc(quotec)) == EOF)
- return (0);
- if (next == quotec || c == ' ' || c == '\t')
- c = next;
- else if (next == '\n') {
- lineno++;
- continue;
- } else
- lungetc(next);
- } else if (c == quotec) {
- *p = '\0';
- break;
- } else if (c == '\0') {
- yyerror("syntax error");
- return (findeol());
- }
- if (p + 1 >= buf + sizeof(buf) - 1) {
- yyerror("string too long");
- return (findeol());
- }
- *p++ = c;
- }
- yylval.string = strdup(buf);
- if (yylval.string == NULL)
- fatal("yylex: strdup");
- return (STRING);
- }
- #define allowed_in_string(x) (isalnum(x) || ispunct(x))
- if (isalnum(c) || c == ':' || c == '_' || c == '*') {
- do {
- *p++ = c;
- if ((unsigned)(p-buf) >= sizeof(buf)) {
- yyerror("string too long");
- return (findeol());
- }
- } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
- lungetc(c);
- *p = '\0';
- if ((token = lookup(buf)) == STRING)
- if ((yylval.string = strdup(buf)) == NULL)
- fatal("yylex: strdup");
- return (token);
- }
- if (c == '\n') {
- yylval.lineno = lineno;
- lineno++;
- }
- if (c == EOF)
- return (0);
- return (c);
- }
- bool
- config_parse(struct config *c, const char *filename)
- {
- log_debug("Parsing config file %s", filename);
- cfg = c;
- file = fopen(filename, "r");
- if (file == NULL) {
- log_warn("parse_config %s", filename);
- return false;
- }
- cfg->config_file = strdup(filename);
- if (cfg->config_file == NULL)
- fatal("config_parse");
- lineno = 1;
- yyparse();
- fclose(file);
- return config_check(c);
- }
|