From d7df8c18407652f5e8998002159a3f80ca2def7c Mon Sep 17 00:00:00 2001 From: op Date: Sun, 11 Feb 2024 09:24:26 +0000 Subject: [PATCH] unify smtpd and makemap table parser These are supposed to parse the same file format but have subtle difference in the handling of comments, continuation lines and escaping. Converge both to the simpler smtpd parser which doesn't handle continuation lines nor escaping, and support comments only at the start of the line. improvements and ok millert@ --- usr.sbin/smtpd/makemap.c | 82 ++++++++++++++--------------------- usr.sbin/smtpd/smtpd.h | 5 ++- usr.sbin/smtpd/table_static.c | 74 +++++-------------------------- usr.sbin/smtpd/util.c | 74 ++++++++++++++++++++++++++++++- 4 files changed, 121 insertions(+), 114 deletions(-) diff --git a/usr.sbin/smtpd/makemap.c b/usr.sbin/smtpd/makemap.c index 2144e83959e..b5d88a8bd46 100644 --- a/usr.sbin/smtpd/makemap.c +++ b/usr.sbin/smtpd/makemap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: makemap.c,v 1.75 2021/06/14 17:58:15 eric Exp $ */ +/* $OpenBSD: makemap.c,v 1.76 2024/02/11 09:24:26 op Exp $ */ /* * Copyright (c) 2008 Gilles Chehade @@ -37,9 +37,8 @@ static void usage(void); static int parse_map(DB *, int *, char *); -static int parse_entry(DB *, int *, char *, size_t, size_t); -static int parse_mapentry(DB *, int *, char *, size_t, size_t); -static int parse_setentry(DB *, int *, char *, size_t, size_t); +static int add_mapentry(DB *, int *, char *, char *, size_t); +static int add_setentry(DB *, int *, char *, size_t); static int make_plain(DBT *, char *); static int make_aliases(DBT *, char *); static char *conf_aliases(char *); @@ -247,9 +246,10 @@ static int parse_map(DB *db, int *dbputs, char *filename) { FILE *fp; - char *line; - size_t len; + char *key, *val, *line = NULL; + size_t linesize = 0; size_t lineno = 0; + int malformed, table_type, r; if (strcmp(filename, "-") == 0) fp = fdopen(0, "r"); @@ -269,55 +269,46 @@ parse_map(DB *db, int *dbputs, char *filename) return 0; } - while ((line = fparseln(fp, &len, &lineno, - NULL, FPARSELN_UNESCCOMM)) != NULL) { - if (!parse_entry(db, dbputs, line, len, lineno)) { + table_type = (type == T_SET) ? T_LIST : T_HASH; + while (parse_table_line(fp, &line, &linesize, &table_type, + &key, &val, &malformed) != -1) { + lineno++; + if (malformed) { + warnx("%s:%zd: invalid entry", source, lineno); + free(line); + fclose(fp); + return 0; + } + if (key == NULL) + continue; + + switch (type) { + case T_PLAIN: + case T_ALIASES: + r = add_mapentry(db, dbputs, key, val, lineno); + break; + case T_SET: + r = add_setentry(db, dbputs, key, lineno); + break; + } + + if (!r) { free(line); fclose(fp); return 0; } - free(line); } + free(line); fclose(fp); return 1; } static int -parse_entry(DB *db, int *dbputs, char *line, size_t len, size_t lineno) -{ - switch (type) { - case T_PLAIN: - case T_ALIASES: - return parse_mapentry(db, dbputs, line, len, lineno); - case T_SET: - return parse_setentry(db, dbputs, line, len, lineno); - } - return 0; -} - -static int -parse_mapentry(DB *db, int *dbputs, char *line, size_t len, size_t lineno) +add_mapentry(DB *db, int *dbputs, char *keyp, char *valp, size_t lineno) { DBT key; DBT val; - char *keyp; - char *valp; - - keyp = line; - while (isspace((unsigned char)*keyp)) - keyp++; - if (*keyp == '\0') - return 1; - - valp = keyp; - strsep(&valp, " \t:"); - if (valp == NULL || valp == keyp) - goto bad; - while (*valp == ':' || isspace((unsigned char)*valp)) - valp++; - if (*valp == '\0') - goto bad; /* Check for dups. */ key.data = keyp; @@ -355,17 +346,10 @@ bad: } static int -parse_setentry(DB *db, int *dbputs, char *line, size_t len, size_t lineno) +add_setentry(DB *db, int *dbputs, char *keyp, size_t lineno) { DBT key; DBT val; - char *keyp; - - keyp = line; - while (isspace((unsigned char)*keyp)) - keyp++; - if (*keyp == '\0') - return 1; val.data = ""; val.size = strlen(val.data) + 1; diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index a0e8add90a8..b4df56c7755 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.681 2024/02/02 22:02:12 gilles Exp $ */ +/* $OpenBSD: smtpd.h,v 1.682 2024/02/11 09:24:26 op Exp $ */ /* * Copyright (c) 2008 Gilles Chehade @@ -1741,6 +1741,9 @@ void log_trace0(const char *, ...) __attribute__((format (printf, 1, 2))); #define log_trace(m, ...) do { if (tracing & (m)) log_trace0(__VA_ARGS__); } while (0) +int parse_table_line(FILE *, char **, size_t *, int *, + char **, char **, int *); + /* waitq.c */ int waitq_wait(void *, void (*)(void *, void *, void *), void *); void waitq_run(void *, void *); diff --git a/usr.sbin/smtpd/table_static.c b/usr.sbin/smtpd/table_static.c index af57038f231..85f2b7a4f81 100644 --- a/usr.sbin/smtpd/table_static.c +++ b/usr.sbin/smtpd/table_static.c @@ -1,4 +1,4 @@ -/* $OpenBSD: table_static.c,v 1.33 2021/06/14 17:58:16 eric Exp $ */ +/* $OpenBSD: table_static.c,v 1.34 2024/02/11 09:24:26 op Exp $ */ /* * Copyright (c) 2013 Eric Faurot @@ -111,80 +111,28 @@ static int table_static_priv_load(struct table_static_priv *priv, const char *path) { FILE *fp; - char *buf = NULL, *p; + char *line = NULL; int lineno = 0; - size_t sz = 0; - ssize_t flen; + size_t linesize = 0; char *keyp; char *valp; - int ret = 0; + int malformed, ret = 0; if ((fp = fopen(path, "r")) == NULL) { log_warn("%s: fopen", path); return 0; } - while ((flen = getline(&buf, &sz, fp)) != -1) { + while (parse_table_line(fp, &line, &linesize, &priv->type, + &keyp, &valp, &malformed) != -1) { lineno++; - if (buf[flen - 1] == '\n') - buf[--flen] = '\0'; - - keyp = buf; - while (isspace((unsigned char)*keyp)) { - ++keyp; - --flen; - } - if (*keyp == '\0') - continue; - while (isspace((unsigned char)keyp[flen - 1])) - keyp[--flen] = '\0'; - if (*keyp == '#') { - if (priv->type == T_NONE) { - keyp++; - while (isspace((unsigned char)*keyp)) - ++keyp; - if (!strcmp(keyp, "@list")) - priv->type = T_LIST; - } - continue; - } - - if (priv->type == T_NONE) { - for (p = keyp; *p; p++) { - if (*p == ' ' || *p == '\t' || *p == ':') { - priv->type = T_HASH; - break; - } - } - if (priv->type == T_NONE) - priv->type = T_LIST; - } - - if (priv->type == T_LIST) { - table_static_priv_add(priv, keyp, NULL); - continue; - } - - /* T_HASH */ - valp = keyp; - strsep(&valp, " \t:"); - if (valp) { - while (*valp) { - if (!isspace((unsigned char)*valp) && - !(*valp == ':' && - isspace((unsigned char)*(valp + 1)))) - break; - ++valp; - } - if (*valp == '\0') - valp = NULL; - } - if (valp == NULL) { - log_warnx("%s: invalid map entry line %d", + if (malformed) { + log_warnx("%s:%d invalid map entry", path, lineno); goto end; } - + if (keyp == NULL) + continue; table_static_priv_add(priv, keyp, valp); } @@ -199,7 +147,7 @@ table_static_priv_load(struct table_static_priv *priv, const char *path) ret = 1; end: - free(buf); + free(line); fclose(fp); return ret; } diff --git a/usr.sbin/smtpd/util.c b/usr.sbin/smtpd/util.c index ba9029ee17e..d481162c897 100644 --- a/usr.sbin/smtpd/util.c +++ b/usr.sbin/smtpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.155 2024/01/03 08:11:15 op Exp $ */ +/* $OpenBSD: util.c,v 1.156 2024/02/11 09:24:26 op Exp $ */ /* * Copyright (c) 2000,2001 Markus Friedl. All rights reserved. @@ -850,3 +850,75 @@ log_trace_verbose(int v) /* Set debug logging in log.c */ log_setverbose(v & TRACE_DEBUG ? 2 : foreground_log); } + +int +parse_table_line(FILE *fp, char **line, size_t *linesize, + int *type, char **key, char **val, int *malformed) +{ + char *keyp, *valp, *p; + ssize_t linelen; + + *key = NULL; + *val = NULL; + *malformed = 0; + + if ((linelen = getline(line, linesize, fp)) == -1) + return (-1); + + keyp = *line; + while (isspace((unsigned char)*keyp)) { + ++keyp; + --linelen; + } + if (*keyp == '\0') + return 0; + while (linelen > 0 && isspace((unsigned char)keyp[linelen - 1])) + keyp[--linelen] = '\0'; + if (*keyp == '#') { + if (*type == T_NONE) { + keyp++; + while (isspace((unsigned char)*keyp)) + ++keyp; + if (!strcmp(keyp, "@list")) + *type = T_LIST; + } + return 0; + } + + if (*type == T_NONE) { + for (p = keyp; *p; p++) { + if (*p == ' ' || *p == '\t' || *p == ':') { + *type = T_HASH; + break; + } + } + if (*type == T_NONE) + *type = T_LIST; + } + + if (*type == T_LIST) { + *key = keyp; + return (0); + } + + /* T_HASH */ + valp = keyp; + strsep(&valp, " \t:"); + if (valp) { + while (*valp) { + if (!isspace((unsigned char)*valp) && + !(*valp == ':' && + isspace((unsigned char)*(valp + 1)))) + break; + ++valp; + } + if (*valp == '\0') + valp = NULL; + } + if (valp == NULL) + *malformed = 1; + + *key = keyp; + *val = valp; + return (0); +} -- 2.20.1