diff options
author | 2014-10-12 18:54:31 +0000 | |
---|---|---|
committer | 2014-10-12 18:54:31 +0000 | |
commit | 37063f1e04404bb025041cdf78025d757112835b (patch) | |
tree | d20afaf771c9cab6104c23c317c083211f5e7cb7 | |
parent | Remove unnecessary `needs-flag' attributes. (diff) | |
download | wireguard-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.c | 148 | ||||
-rw-r--r-- | usr.sbin/smtpd/rfc822.h | 43 |
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 |