import alternative message parser (not used yet).
authoreric <eric@openbsd.org>
Thu, 23 Aug 2018 10:07:06 +0000 (10:07 +0000)
committereric <eric@openbsd.org>
Thu, 23 Aug 2018 10:07:06 +0000 (10:07 +0000)
usr.sbin/smtpd/rfc5322.c [new file with mode: 0644]
usr.sbin/smtpd/rfc5322.h [new file with mode: 0644]

diff --git a/usr.sbin/smtpd/rfc5322.c b/usr.sbin/smtpd/rfc5322.c
new file mode 100644 (file)
index 0000000..a6740bf
--- /dev/null
@@ -0,0 +1,264 @@
+/*     $OpenBSD: rfc5322.c,v 1.1 2018/08/23 10:07:06 eric Exp $        */
+
+/*
+ * Copyright (c) 2018 Eric Faurot <eric@openbsd.org>
+ *
+ * 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 <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rfc5322.h"
+
+struct buf {
+       char    *buf;
+       size_t   bufsz;
+       size_t   buflen;
+       size_t   bufmax;
+};
+
+static int buf_alloc(struct buf *, size_t);
+static int buf_grow(struct buf *, size_t);
+static int buf_cat(struct buf *, const char *);
+
+struct rfc5322_parser {
+       const char      *line;
+       int              state;         /* last parser state */
+       int              next;          /* parser needs data */
+       int              unfold;
+       const char      *currhdr;
+       struct buf       hdr;
+       struct buf       val;
+};
+
+struct rfc5322_parser *
+rfc5322_parser_new(void)
+{
+       struct rfc5322_parser *parser;
+
+       parser = calloc(1, sizeof(*parser));
+       if (parser == NULL)
+               return NULL;
+
+       rfc5322_clear(parser);
+       parser->hdr.bufmax = 1024;
+       parser->val.bufmax = 65536;
+
+       return parser;
+}
+
+void
+rfc5322_free(struct rfc5322_parser *parser)
+{
+       free(parser->hdr.buf);
+       free(parser->val.buf);
+       free(parser);
+}
+
+void
+rfc5322_clear(struct rfc5322_parser *parser)
+{
+       parser->line = NULL;
+       parser->state = RFC5322_NONE;
+       parser->next = 0;
+       parser->hdr.buflen = 0;
+       parser->val.buflen = 0;
+}
+
+int
+rfc5322_push(struct rfc5322_parser *parser, const char *line)
+{
+       if (parser->line) {
+               errno = EALREADY;
+               return -1;
+       }
+
+       parser->line = line;
+       parser->next = 0;
+
+       return 0;
+}
+
+int
+rfc5322_unfold_header(struct rfc5322_parser *parser)
+{
+       if (parser->unfold) {
+               errno = EALREADY;
+               return -1;
+       }
+
+       if (parser->currhdr == NULL) {
+               errno = EOPNOTSUPP;
+               return -1;
+       }
+
+       if (buf_cat(&parser->val, parser->currhdr) == -1)
+               return -1;
+
+       parser->currhdr = NULL;
+       parser->unfold = 1;
+
+       return 0;
+}
+
+static int
+_rfc5322_next(struct rfc5322_parser *parser, struct rfc5322_result *res)
+{
+       size_t len;
+       const char *pos, *line;
+
+       line = parser->line;
+
+       switch(parser->state) {
+
+       case RFC5322_HEADER_START:
+       case RFC5322_HEADER_CONT:
+               res->hdr = parser->hdr.buf;
+
+               if (line && (line[0] == ' ' || line[0] == '\t')) {
+                       parser->line = NULL;
+                       parser->next = 1;
+                       if (parser->unfold) {
+                               if (buf_cat(&parser->val, "\n") == -1 ||
+                                   buf_cat(&parser->val, line) == -1)
+                                       return -1;
+                       }
+                       res->value = line;
+                       return RFC5322_HEADER_CONT;
+               }
+
+               if (parser->unfold) {
+                       parser->val.buflen = 0;
+                       parser->unfold = 0;
+                       res->value = parser->val.buf;
+               }
+               return RFC5322_HEADER_END;
+
+       case RFC5322_NONE:
+       case RFC5322_HEADER_END:
+               if (line && (pos = strchr(line, ':'))) {
+                       len = pos - line;
+                       if (buf_grow(&parser->hdr, len + 1) == -1)
+                               return -1;
+                       (void)memcpy(parser->hdr.buf, line, len);
+                       parser->hdr.buf[len] = '\0';
+                       parser->hdr.buflen = len + 1;
+                       parser->line = NULL;
+                       parser->next = 1;
+                       parser->currhdr = pos + 1;
+                       res->hdr = parser->hdr.buf;
+                       res->value = pos + 1;
+                       return RFC5322_HEADER_START;
+               }
+
+               return RFC5322_END_OF_HEADERS;
+
+       case RFC5322_END_OF_HEADERS:
+               if (line == NULL)
+                       return RFC5322_END_OF_MESSAGE;
+
+               if (line[0] == '\0') {
+                       parser->line = NULL;
+                       parser->next = 1;
+                       res->value = line;
+                       return RFC5322_BODY_START;
+               }
+
+               errno = EFTYPE;
+               return -1;
+
+       case RFC5322_BODY_START:
+       case RFC5322_BODY:
+               if (line == NULL)
+                       return RFC5322_END_OF_MESSAGE;
+
+               parser->line = NULL;
+               parser->next = 1;
+               res->value = line;
+               return RFC5322_BODY;
+
+       case RFC5322_END_OF_MESSAGE:
+               errno = ENOMSG;
+               return -1;
+
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+}
+
+int
+rfc5322_next(struct rfc5322_parser *parser, struct rfc5322_result *res)
+{
+       memset(res, 0, sizeof(*res));
+
+       if (parser->next)
+               return RFC5322_NONE;
+
+       return (parser->state = _rfc5322_next(parser, res));
+}
+
+static int
+buf_alloc(struct buf *b, size_t need)
+{
+       char *buf;
+       size_t alloc;
+
+       if (b->buf && b->bufsz >= need)
+               return 0;
+
+       if (need >= b->bufmax) {
+               errno = ERANGE;
+               return -1;
+       }
+
+#define N 256
+       alloc = N * (need / N) + ((need % N) ? N : 0);
+#undef N
+       buf = reallocarray(b->buf, alloc, 1);
+       if (buf == NULL)
+               return -1;
+
+       b->buf = buf;
+       b->bufsz = alloc;
+
+       return 0;
+}
+
+static int
+buf_grow(struct buf *b, size_t sz)
+{
+       if (SIZE_T_MAX - b->buflen <= sz) {
+               errno = ERANGE;
+               return -1;
+       }
+
+       return buf_alloc(b, b->buflen + sz);
+}
+
+static int
+buf_cat(struct buf *b, const char *s)
+{
+       size_t len = strlen(s);
+
+       if (buf_grow(b, len + 1) == -1)
+               return -1;
+
+       (void)memmove(b->buf + b->buflen, s, len + 1);
+       b->buflen += len;
+       return 0;
+}
diff --git a/usr.sbin/smtpd/rfc5322.h b/usr.sbin/smtpd/rfc5322.h
new file mode 100644 (file)
index 0000000..0979bd4
--- /dev/null
@@ -0,0 +1,41 @@
+/*     $OpenBSD: rfc5322.h,v 1.1 2018/08/23 10:07:06 eric Exp $        */
+
+/*
+ * Copyright (c) 2018 Eric Faurot <eric@openbsd.org>
+ *
+ * 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.
+ */
+
+struct rfc5322_result {
+       const char      *hdr;
+       const char      *value;
+};
+
+#define        RFC5322_ERR             -1
+#define        RFC5322_NONE            0
+#define        RFC5322_HEADER_START    1
+#define        RFC5322_HEADER_CONT     2
+#define        RFC5322_HEADER_END      3
+#define        RFC5322_END_OF_HEADERS  4
+#define        RFC5322_BODY_START      5
+#define        RFC5322_BODY            6
+#define        RFC5322_END_OF_MESSAGE  7
+
+struct rfc5322_parser;
+
+struct rfc5322_parser *rfc5322_parser_new(void);
+void rfc5322_free(struct rfc5322_parser *);
+void rfc5322_clear(struct rfc5322_parser *);
+int rfc5322_push(struct rfc5322_parser *, const char *);
+int rfc5322_next(struct rfc5322_parser *, struct rfc5322_result *);
+int rfc5322_unfold_header(struct rfc5322_parser *);