summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgilles <gilles@openbsd.org>2014-10-12 18:54:31 +0000
committergilles <gilles@openbsd.org>2014-10-12 18:54:31 +0000
commit37063f1e04404bb025041cdf78025d757112835b (patch)
treed20afaf771c9cab6104c23c317c083211f5e7cb7
parentRemove unnecessary `needs-flag' attributes. (diff)
downloadwireguard-openbsd-37063f1e04404bb025041cdf78025d757112835b.tar.xz
wireguard-openbsd-37063f1e04404bb025041cdf78025d757112835b.zip
to rewrite domain on incoming mails, we need to be able to extract
rfc822 addresses from some headers and parse them into a structure that we can easily manipulate. this implementation will parse addresses in the following formats: user, user <addr>, "user" <addr>, "user name" <addr>
-rw-r--r--usr.sbin/smtpd/rfc822.c148
-rw-r--r--usr.sbin/smtpd/rfc822.h43
2 files changed, 191 insertions, 0 deletions
diff --git a/usr.sbin/smtpd/rfc822.c b/usr.sbin/smtpd/rfc822.c
new file mode 100644
index 00000000000..b598fa1ff07
--- /dev/null
+++ b/usr.sbin/smtpd/rfc822.c
@@ -0,0 +1,148 @@
+/* $OpenBSD: rfc822.c,v 1.1 2014/10/12 18:54:31 gilles Exp $ */
+
+/*
+ * Copyright (c) 2014 Gilles Chehade <gilles@poolp.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 <sys/types.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "rfc822.h"
+
+static int
+parse_addresses(struct rfc822_parser *rp, const char *buffer, size_t len)
+{
+ const char *s;
+ char *wptr;
+ struct rfc822_address *ra;
+
+ s = buffer;
+
+ /* skip over whitespaces */
+ for (s = buffer; *s && isspace(*s); ++s, len--)
+ ;
+
+ /* we should now pointing to the beginning of a recipient */
+ if (*s == '\0')
+ return 0;
+
+ ra = calloc(1, sizeof *ra);
+ if (ra == NULL)
+ return -1;
+
+ wptr = ra->name;
+ for (; len; s++, len--) {
+ if (*s == '(' && !rp->escape && !rp->quote)
+ rp->comment++;
+ if (*s == '"' && !rp->escape && !rp->comment)
+ rp->quote = !rp->quote;
+ if (!rp->comment && !rp->quote && !rp->escape) {
+ if (*s == '<' && rp->bracket)
+ return 0;
+ if (*s == '>' && !rp->bracket)
+ return 0;
+
+ if (*s == '<') {
+ wptr = ra->address;
+ rp->bracket++;
+ continue;
+ }
+ if (*s == '>') {
+ rp->bracket--;
+ continue;
+ }
+ if (*s == ',' || *s == ';')
+ break;
+ }
+ if (*s == ')' && !rp->escape && !rp->quote && rp->comment)
+ rp->comment--;
+ if (*s == '\\' && !rp->escape && !rp->comment && !rp->quote)
+ rp->escape = 1;
+ else
+ rp->escape = 0;
+ *wptr++ = *s;
+ }
+
+ /* no value, malformed header */
+ if (ra->name[0] == '\0' && ra->address[0] == '\0')
+ return 0;
+
+ /* no <>, use name as address */
+ if (ra->address[0] == '\0') {
+ memcpy(ra->address, ra->name, sizeof ra->address);
+ memset(ra->name, 0, sizeof ra->name);
+ }
+
+ /* strip first trailing whitespace from name */
+ wptr = &ra->name[0] + strlen(ra->name);
+ while (wptr != &ra->name[0]) {
+ if (*wptr && ! isspace(*wptr))
+ break;
+ *wptr-- = '\0';
+ }
+
+ TAILQ_INSERT_TAIL(&rp->addresses, ra, next);
+
+ /* do we have more to process ? */
+ for (; *s; ++s, --len)
+ if (*s == ',' || *s == ';')
+ break;
+
+ /* nope, we're done */
+ if (*s == '\0')
+ return 1;
+
+ /* there's more to come */
+ if (*s == ',' || *s == ';') {
+ s++;
+ len--;
+ }
+ if (len)
+ return parse_addresses(rp, s, len);
+ return 1;
+}
+
+void
+rfc822_parser_init(struct rfc822_parser *rp)
+{
+ memset(rp, 0, sizeof *rp);
+ TAILQ_INIT(&rp->addresses);
+}
+
+void
+rfc822_parser_reset(struct rfc822_parser *rp)
+{
+ struct rfc822_address *ra;
+
+ while ((ra = TAILQ_FIRST(&rp->addresses))) {
+ TAILQ_REMOVE(&rp->addresses, ra, next);
+ free(ra);
+ }
+ memset(rp, 0, sizeof *rp);
+}
+
+int
+rfc822_parser_feed(struct rfc822_parser *rp, const char *line)
+{
+ return parse_addresses(rp, line, strlen(line));
+}
diff --git a/usr.sbin/smtpd/rfc822.h b/usr.sbin/smtpd/rfc822.h
new file mode 100644
index 00000000000..0e602e23d21
--- /dev/null
+++ b/usr.sbin/smtpd/rfc822.h
@@ -0,0 +1,43 @@
+/* $OpenBSD: rfc822.h,v 1.1 2014/10/12 18:54:31 gilles Exp $ */
+
+/*
+ * Copyright (c) 2014 Gilles Chehade <gilles@poolp.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.
+ */
+
+#ifndef _RFC822_H_
+#define _RFC822_H_
+
+#define RFC822_MAX_LINE_SIZE 998
+
+struct rfc822_address {
+ TAILQ_ENTRY(rfc822_address) next;
+ char name[RFC822_MAX_LINE_SIZE+1];
+ char address[RFC822_MAX_LINE_SIZE+1];
+};
+
+struct rfc822_parser {
+ TAILQ_HEAD(addresses, rfc822_address) addresses;
+
+ uint8_t quote;
+ uint8_t comment;
+ uint8_t escape;
+ uint8_t bracket;
+};
+
+void rfc822_parser_init(struct rfc822_parser *);
+void rfc822_parser_reset(struct rfc822_parser *);
+int rfc822_parser_feed(struct rfc822_parser *, const char *);
+
+#endif