From: eric Date: Thu, 23 Aug 2018 10:07:06 +0000 (+0000) Subject: import alternative message parser (not used yet). X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=ca4531c30444e11d38a8ee82f32489a5f8fe31ed;p=openbsd import alternative message parser (not used yet). --- diff --git a/usr.sbin/smtpd/rfc5322.c b/usr.sbin/smtpd/rfc5322.c new file mode 100644 index 00000000000..a6740bf8a61 --- /dev/null +++ b/usr.sbin/smtpd/rfc5322.c @@ -0,0 +1,264 @@ +/* $OpenBSD: rfc5322.c,v 1.1 2018/08/23 10:07:06 eric Exp $ */ + +/* + * Copyright (c) 2018 Eric Faurot + * + * 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 +#include +#include +#include +#include + +#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 index 00000000000..0979bd4ccb3 --- /dev/null +++ b/usr.sbin/smtpd/rfc5322.h @@ -0,0 +1,41 @@ +/* $OpenBSD: rfc5322.h,v 1.1 2018/08/23 10:07:06 eric Exp $ */ + +/* + * Copyright (c) 2018 Eric Faurot + * + * 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 *);