unify smtpd and makemap table parser
authorop <op@openbsd.org>
Sun, 11 Feb 2024 09:24:26 +0000 (09:24 +0000)
committerop <op@openbsd.org>
Sun, 11 Feb 2024 09:24:26 +0000 (09:24 +0000)
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
usr.sbin/smtpd/smtpd.h
usr.sbin/smtpd/table_static.c
usr.sbin/smtpd/util.c

index 2144e83..b5d88a8 100644 (file)
@@ -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 <gilles@poolp.org>
@@ -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  = "<set>";
        val.size = strlen(val.data) + 1;
index a0e8add..b4df56c 100644 (file)
@@ -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 <gilles@poolp.org>
@@ -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 *);
index af57038..85f2b7a 100644 (file)
@@ -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 <eric@openbsd.org>
@@ -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;
 }
index ba9029e..d481162 100644 (file)
@@ -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);
+}