commit - 803cdd74ad2746c83be456e70b251067e2007c04
commit + 40cd76f4447b88dd8a31fe5452837b7b890ad1a7
blob - cd8936cf464c880415aeeae99c4c3de9758604e1
blob + 7e6d565348258244ea4df4c2258f1a93df024bd2
--- Makefile
+++ Makefile
BINDIR= ${LOCALBASE}/libexec/smtpd/
MANDIR= ${LOCALBASE}/man/man
-SRCS+= main.c
+SRCS+= main.c mheader.c
CFLAGS+=-I${LOCALBASE}/include
CFLAGS+=-Wall -I${.CURDIR}
blob - c1fd990650431bd9f6ff9d6e22c3b0722455f84e
blob + 9709fee64e92a81889ce55e309a7dbddb8d81ffd
--- filter-dkimsign.8
+++ filter-dkimsign.8
Defaults to
.Ar simple/simple .
.It Fl d Ar domain
-The domain where the public key can be found.
+The
+.Ar domain
+where the public key can be found.
+This option can be specified multiple times to select the best
+.Ar domain
+during signing.
+If specified multiple times it looks at the domain component of the first
+mailbox in the from-header and tries to find a match.
+If no exact match can be found it looks for the closest parent
+.Ar domain .
+If no matches can be the first
+.Ar domain
+specified will be used.
.It Fl h Ar headers
The email headers which are included in the mail signature.
Per RFC this option requires at least the from header to be included.
blob - 9e8b8070a223394e3d9d10ba129bf31f508a64df
blob + e226617f1de01bf3e6891d29fc3ce0f5a20794aa
--- main.c
+++ main.c
#include <unistd.h>
#include "opensmtpd.h"
+#include "mheader.h"
struct dkim_signature {
char *signature;
static long long addexpire = 0;
static int addheaders = 0;
-static char *domain = NULL;
+static char **domain = NULL;
+static size_t ndomains = 0;
static char *selector = NULL;
static EVP_PKEY *pkey;
int dkim_signature_printf(struct dkim_message *, char *, ...)
__attribute__((__format__ (printf, 2, 3)));
int dkim_signature_normalize(struct dkim_message *);
+const char *dkim_domain_select(struct dkim_message *, char *);
int dkim_signature_need(struct dkim_message *, size_t);
int dkim_sign_init(struct dkim_message *);
osmtpd_err(1, "Invalid canonicalization");
break;
case 'd':
- domain = optarg;
+ if ((domain = reallocarray(domain, ndomains + 1,
+ sizeof(*domain))) == NULL)
+ osmtpd_err(1, "malloc");
+ domain[ndomains++] = optarg;
break;
case 'h':
dkim_headers_set(optarg);
message->err = 0;
if (!dkim_signature_printf(message,
- "DKIM-Signature: v=%s; a=%s-%s; c=%s/%s; d=%s; s=%s; ", "1",
+ "DKIM-Signature: v=%s; a=%s-%s; c=%s/%s; s=%s; ", "1",
cryptalg, hashalg,
canonheader == CANON_SIMPLE ? "simple" : "relaxed",
- canonbody == CANON_SIMPLE ? "simple" : "relaxed",
- domain, selector))
+ canonbody == CANON_SIMPLE ? "simple" : "relaxed", selector))
return NULL;
if (addheaders > 0 && !dkim_signature_printf(message, "z="))
return NULL;
char bbh[EVP_MAX_MD_SIZE];
char bh[(((sizeof(bbh) + 2) / 3) * 4) + 1];
char *b;
+ const char *sdomain = domain[0], *tsdomain;
time_t now;
ssize_t i;
size_t linelen;
dkim_errx(message, "Failed to update digest context");
return;
}
+ if ((tsdomain = dkim_domain_select(message, message->headers[i])) != NULL)
+ sdomain = tsdomain;
/* We're done with the cached header after hashing */
for (tmp = message->headers[i]; tmp[0] != ':'; tmp++) {
if (tmp[0] == ' ' || tmp[0] == '\t')
message->headers[i]))
return;
}
- dkim_signature_printf(message, "; b=");
+ dkim_signature_printf(message, "; d=%s; b=", sdomain);
if (!dkim_signature_normalize(message))
return;
if ((tmp = strdup(message->signature.signature)) == NULL) {
sig->len += len;
va_end(ap);
return 1;
+}
+
+const char *
+dkim_domain_select(struct dkim_message *message, char *from)
+{
+ char *mdomain0, *mdomain;
+ size_t i;
+
+ if ((mdomain = mdomain0 = osmtpd_mheader_from_domain(from)) == NULL) {
+ if (errno != EINVAL) {
+ dkim_err(message, "Couldn't parse from header");
+ return NULL;
+ }
+ return NULL;
+ }
+
+ while (mdomain != NULL && mdomain[0] != '\0') {
+ for (i = 0; i < ndomains; i++) {
+ if (strcasecmp(mdomain, domain[i]) == 0) {
+ free(mdomain0);
+ return domain[i];
+ }
+ }
+ if ((mdomain = strchr(mdomain, '.')) != NULL)
+ mdomain++;
+ }
+ free(mdomain0);
+ return NULL;
}
int
blob - /dev/null
blob + bf83d2c34a9425bae381902fc43fbcc08d7f1aef (mode 644)
--- /dev/null
+++ mheader.c
+/*
+ * Copyright (c) 2020 Martijn van Duren <martijn@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 <stddef.h>
+#include <string.h>
+#include <strings.h>
+
+#include "mheader.h"
+
+char *
+osmtpd_mheader_skip_sp(char *ptr, int optional)
+{
+ if (ptr[0] == 0x20)
+ return ptr + 1;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_htab(char *ptr, int optional)
+{
+ if (ptr[0] == 0x9)
+ return ptr + 1;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_wsp(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_sp(start, 0)) != NULL ||
+ (ptr = osmtpd_mheader_skip_htab(start, 0)) != NULL)
+ return ptr;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_crlf(char *ptr, int optional)
+{
+ if (ptr[0] == 13 && ptr[1] == 10)
+ return ptr + 2;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_vchar(char *ptr, int optional)
+{
+ if (ptr[0] >= 0x21 && ptr[0] <= 0x7e)
+ return ptr + 1;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_lf(char *ptr, int optional)
+{
+ if (ptr[0] == 0xa)
+ return ptr + 1;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_cr(char *ptr, int optional)
+{
+ if (ptr[0] == 0xd)
+ return ptr + 1;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_alpha(char *ptr, int optional)
+{
+ if ((ptr[0] >= 0x41 && ptr[0] <= 0x5a) ||
+ (ptr[0] >= 0x61 && ptr[0] <= 0x7a))
+ return ptr + 1;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_digit(char *ptr, int optional)
+{
+ if (ptr[0] >= 0x30 && ptr[0] <= 0x39)
+ return ptr + 1;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_dquote(char *ptr, int optional)
+{
+ if (ptr[0] == 0x22)
+ return ptr + 1;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_obs_fws(char *ptr, int optional)
+{
+ char *start = ptr, *prev;
+
+ if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ prev = ptr;
+ while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
+ prev = ptr;
+
+ ptr = prev;
+ while (1) {
+ if ((ptr = osmtpd_mheader_skip_crlf(ptr, 0)) == NULL)
+ return prev;
+ if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
+ return prev;
+ prev = ptr;
+ while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
+ prev = ptr;
+ ptr = prev;
+ }
+}
+
+char *
+osmtpd_mheader_skip_fws(char *ptr, int optional)
+{
+ char *start = ptr, *prev = ptr;
+
+ while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
+ prev = ptr;
+ if ((ptr = osmtpd_mheader_skip_crlf(prev, 1)) == prev)
+ ptr = start;
+ if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
+ return osmtpd_mheader_skip_obs_fws(start, optional);
+ prev = ptr;
+ while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
+ prev = ptr;
+ return prev;
+}
+
+char *
+osmtpd_mheader_skip_obs_no_ws_ctl(char *ptr, int optional)
+{
+ if ((ptr[0] >= 1 && ptr[0] <= 8) || ptr[0] == 11 || ptr[0] == 12 ||
+ (ptr[0] >= 14 && ptr[0] <= 31) || ptr[0] == 127)
+ return ptr + 1;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_obs_ctext(char *ptr, int optional)
+{
+ return osmtpd_mheader_skip_obs_no_ws_ctl(ptr, optional);
+}
+
+char *
+osmtpd_mheader_skip_ctext(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr[0] >= 33 && ptr[0] <= 39) || (ptr[0] >= 42 && ptr[0] <= 91) ||
+ (ptr[0] >= 93 && ptr[0] <= 126))
+ return ptr + 1;
+ if ((ptr = osmtpd_mheader_skip_obs_ctext(ptr, 0)) != NULL)
+ return ptr;
+ return optional ? start : NULL;
+}
+
+char *
+osmtpd_mheader_skip_obs_qp(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if (ptr[0] == '\\' && (
+ (ptr = osmtpd_mheader_skip_obs_no_ws_ctl(start + 1, 0)) != NULL ||
+ (ptr = osmtpd_mheader_skip_lf(start + 1, 0)) != NULL ||
+ (ptr = osmtpd_mheader_skip_cr(start + 1, 0)) != NULL))
+ return ptr;
+ return optional ? start : NULL;
+}
+
+char *
+osmtpd_mheader_skip_quoted_pair(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if (ptr[0] == '\\' && (
+ (ptr = osmtpd_mheader_skip_vchar(start + 1, 0)) != NULL ||
+ (ptr = osmtpd_mheader_skip_wsp(start + 1, 0)) != NULL))
+ return ptr;
+ return osmtpd_mheader_skip_obs_qp(start, optional);
+}
+
+char *
+osmtpd_mheader_skip_ccontent(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_ctext(ptr, 0)) != NULL)
+ return ptr;
+ if ((ptr = osmtpd_mheader_skip_quoted_pair(start, 0)) != NULL)
+ return ptr;
+ if ((ptr = osmtpd_mheader_skip_comment(start, 0)) != NULL)
+ return ptr;
+ return optional ? start : NULL;
+}
+
+char *
+osmtpd_mheader_skip_comment(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if (ptr++[0] != '(')
+ return optional ? start : NULL;
+ while (1) {
+ ptr = osmtpd_mheader_skip_fws(ptr, 1);
+ if (ptr[0] == ')')
+ return ptr + 1;
+ if ((ptr = osmtpd_mheader_skip_ccontent(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ }
+}
+
+char *
+osmtpd_mheader_skip_cfws(char *ptr, int optional)
+{
+ char *start = ptr, *prev;
+
+ while (1) {
+ ptr = osmtpd_mheader_skip_fws(ptr, 1);
+ prev = ptr;
+ if ((ptr = osmtpd_mheader_skip_comment(ptr, 0)) == NULL) {
+ ptr = prev;
+ break;
+ }
+ }
+ return ptr == start && !optional ? NULL : ptr;
+}
+
+char *
+osmtpd_mheader_skip_atext(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_alpha(start, 0)) != NULL ||
+ (ptr = osmtpd_mheader_skip_digit(start, 0)) != NULL)
+ return ptr;
+ ptr = start;
+ if (ptr[0] == '!' || ptr[0] == '#' || ptr[0] == '$' || ptr[0] == '%' ||
+ ptr[0] == '&' || ptr[0] == '\'' || ptr[0] == '*' || ptr[0] == '+' ||
+ ptr[0] == '-' || ptr[0] == '/' || ptr[0] == '=' || ptr[0] == '?' ||
+ ptr[0] == '^' || ptr[0] == '_' || ptr[0] == '`' || ptr[0] == '{' ||
+ ptr[0] == '|' || ptr[0] == '}' || ptr[0] == '~')
+ return ptr + 1;
+ return optional ? start : NULL;
+}
+
+char *
+osmtpd_mheader_skip_atom(char *ptr, int optional)
+{
+ char *start = ptr, *prev;
+
+ ptr = osmtpd_mheader_skip_cfws(ptr, 1);
+ if ((ptr = osmtpd_mheader_skip_atext(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ do {
+ prev = ptr;
+ ptr = osmtpd_mheader_skip_atext(ptr, 1);
+ } while (prev != ptr);
+ return osmtpd_mheader_skip_cfws(ptr, 1);
+}
+
+char *
+osmtpd_mheader_skip_dot_atom_text(char *ptr, int optional)
+{
+ char *start = ptr, *prev;
+
+ if ((ptr = osmtpd_mheader_skip_atext(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ do {
+ prev = ptr;
+ ptr = osmtpd_mheader_skip_atext(ptr, 1);
+ } while (ptr != prev);
+
+ while (ptr[0] == '.') {
+ ptr++;
+ if ((ptr = osmtpd_mheader_skip_atext(ptr, 0)) == NULL)
+ return prev;
+ do {
+ prev = ptr;
+ ptr = osmtpd_mheader_skip_atext(ptr, 1);
+ } while (ptr != prev);
+ }
+ return ptr;
+}
+
+char *
+osmtpd_mheader_skip_dot_atom(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ ptr = osmtpd_mheader_skip_cfws(ptr, 1);
+ if ((ptr = osmtpd_mheader_skip_dot_atom_text(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ return osmtpd_mheader_skip_cfws(ptr, 1);
+}
+
+
+char *
+osmtpd_mheader_skip_obs_qtext(char *ptr, int optional)
+{
+ return osmtpd_mheader_skip_obs_no_ws_ctl(ptr, optional);
+}
+
+char *
+osmtpd_mheader_skip_qtext(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if (ptr[0] == 33 || (ptr[0] >= 35 && ptr[0] <= 91) ||
+ (ptr[0] >= 93 && ptr[0] <= 126))
+ return ptr + 1;
+ if ((ptr = osmtpd_mheader_skip_obs_qtext(ptr, 0)) != NULL)
+ return ptr;
+ return optional ? start : NULL;
+}
+
+char *
+osmtpd_mheader_skip_qcontent(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_qtext(ptr, 0)) != NULL)
+ return ptr;
+ return osmtpd_mheader_skip_quoted_pair(start, optional);
+}
+
+char *
+osmtpd_mheader_skip_quoted_string(char *ptr, int optional)
+{
+ char *start = ptr, *prev;
+
+ ptr = osmtpd_mheader_skip_cfws(ptr, 1);
+ if ((ptr = osmtpd_mheader_skip_dquote(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ prev = ptr;
+ while (1) {
+ ptr = osmtpd_mheader_skip_fws(ptr, 1);
+ if ((ptr = osmtpd_mheader_skip_qcontent(ptr, 0)) == NULL)
+ break;
+ prev = ptr;
+ }
+ if ((ptr = osmtpd_mheader_skip_dquote(prev, 0)) == NULL)
+ return optional ? start : NULL;
+ return osmtpd_mheader_skip_cfws(ptr, 1);
+}
+
+char *
+osmtpd_mheader_skip_word(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) != NULL)
+ return ptr;
+ return osmtpd_mheader_skip_quoted_string(start, optional);
+}
+
+char *
+osmtpd_mheader_skip_obs_phrase(char *ptr, int optional)
+{
+ char *start = ptr, *prev;
+
+ if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ while (1) {
+ prev = ptr;
+ if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) != NULL)
+ continue;
+ ptr = prev;
+ if (ptr[0] == '.')
+ continue;
+ if ((ptr = osmtpd_mheader_skip_cfws(ptr, 0)) != NULL)
+ continue;
+ return prev;
+ }
+}
+
+char *
+osmtpd_mheader_skip_phrase(char *ptr, int optional)
+{
+ /* obs-phrase is a superset of phrae */
+ return osmtpd_mheader_skip_obs_phrase(ptr, optional);
+#if 0
+ char *start = ptr, *prev;
+
+ if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ while (1) {
+ prev = ptr;
+ if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
+ return prev;
+ }
+#endif
+}
+
+char *
+osmtpd_mheader_skip_obs_local_part(char *ptr, int optional)
+{
+ char *start = ptr, *prev;
+
+ if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ prev = ptr;
+ while (ptr[0] == '.') {
+ ptr++;
+ if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
+ return prev;
+ prev = ptr;
+ }
+ return ptr;
+}
+
+char *
+osmtpd_mheader_skip_local_part(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_dot_atom(ptr, 0)) != NULL)
+ return ptr;
+ ptr = start;
+ if ((ptr = osmtpd_mheader_skip_quoted_string(ptr, 0)) != NULL)
+ return ptr;
+ return osmtpd_mheader_skip_obs_local_part(start, optional);
+}
+
+char *
+osmtpd_mheader_skip_obs_dtext(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_obs_no_ws_ctl(ptr, 0)) != NULL)
+ return ptr;
+ return osmtpd_mheader_skip_quoted_pair(start, optional);
+}
+
+char *
+osmtpd_mheader_skip_dtext(char *ptr, int optional)
+{
+ if ((ptr[0] >= 33 && ptr[0] <= 90) || (ptr[0] >= 94 && ptr[0] <= 126))
+ return ptr + 1;
+ return osmtpd_mheader_skip_obs_dtext(ptr, optional);
+
+}
+
+char *
+osmtpd_mheader_skip_domain_literal(char *ptr, int optional)
+{
+ char *start = ptr, *prev;
+
+ ptr = osmtpd_mheader_skip_cfws(ptr, 1);
+ if (ptr++[0] != '[')
+ return optional ? start : NULL;
+ while (1) {
+ ptr = osmtpd_mheader_skip_fws(ptr, 1);
+ prev = ptr;
+ if ((ptr = osmtpd_mheader_skip_dtext(ptr, 0)) == NULL) {
+ ptr = prev;
+ break;
+ }
+ }
+ if (ptr[0] != ']')
+ return optional ? start : NULL;
+ return osmtpd_mheader_skip_cfws(ptr, 1);
+}
+
+char *
+osmtpd_mheader_skip_obs_domain(char *ptr, int optional)
+{
+ char *start = ptr, *prev;
+
+ if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ prev = ptr;
+ while (1) {
+ if (ptr++[0] != '.')
+ return prev;
+ if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) == NULL)
+ return prev;
+ prev = ptr;
+ }
+}
+
+char *
+osmtpd_mheader_skip_domain(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_dot_atom(start, 0)) != NULL)
+ return ptr;
+ if ((ptr = osmtpd_mheader_skip_domain_literal(start, 0)) != NULL)
+ return ptr;
+ return osmtpd_mheader_skip_obs_domain(start, optional);
+}
+
+char *
+osmtpd_mheader_skip_display_name(char *ptr, int optional)
+{
+ return osmtpd_mheader_skip_phrase(ptr, optional);
+}
+
+char *
+osmtpd_mheader_skip_obs_domain_list(char *ptr, int optional)
+{
+ char *start = ptr, *prev;
+
+ while (1) {
+ if (ptr[0] == ',') {
+ ptr++;
+ prev = ptr;
+ continue;
+ } else if ((ptr = osmtpd_mheader_skip_cfws(ptr, 0)) != NULL) {
+ prev = ptr;
+ continue;
+ }
+ break;
+ }
+ ptr = prev;
+
+ if (ptr++[0] != '@')
+ return optional ? start : NULL;
+ if ((ptr = osmtpd_mheader_skip_domain(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ while (1) {
+ if (ptr[0] != ',')
+ break;
+ ptr++;
+ ptr = osmtpd_mheader_skip_cfws(ptr, 1);
+ if (ptr[0] != '@')
+ continue;
+ prev = ptr;
+ if ((ptr = osmtpd_mheader_skip_domain(ptr + 1, 0)) == NULL) {
+ ptr = prev;
+ break;
+ }
+ }
+ return ptr;
+}
+
+char *
+osmtpd_mheader_skip_obs_route(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_obs_domain_list(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ if (ptr++[0] != ':')
+ return optional ? start : NULL;
+ return ptr;
+}
+
+char *
+osmtpd_mheader_skip_addr_spec(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_local_part(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ if (ptr++[0] != '@')
+ return optional ? start : NULL;
+ if ((ptr = osmtpd_mheader_skip_domain(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ return ptr;
+}
+
+char *
+osmtpd_mheader_skip_obs_angle_addr(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ ptr = osmtpd_mheader_skip_cfws(ptr, 1);
+ if (ptr++[0] != '<')
+ return optional ? start : NULL;
+ if ((ptr = osmtpd_mheader_skip_obs_route(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ if ((ptr = osmtpd_mheader_skip_addr_spec(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ if (ptr++[0] != '>')
+ return optional ? start : NULL;
+ return osmtpd_mheader_skip_cfws(ptr, 1);
+}
+
+char *
+osmtpd_mheader_skip_angle_addr(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ ptr = osmtpd_mheader_skip_cfws(ptr, 1);
+ if (ptr++[0] != '<')
+ return osmtpd_mheader_skip_obs_angle_addr(start, optional);
+ if ((ptr = osmtpd_mheader_skip_addr_spec(ptr, 0)) == NULL)
+ return osmtpd_mheader_skip_obs_angle_addr(start, optional);
+ if (ptr++[0] != '>')
+ return osmtpd_mheader_skip_obs_angle_addr(start, optional);
+ return osmtpd_mheader_skip_cfws(ptr, 1);
+}
+
+char *
+osmtpd_mheader_skip_name_addr(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ ptr = osmtpd_mheader_skip_display_name(ptr, 1);
+ if ((ptr = osmtpd_mheader_skip_angle_addr(ptr, 0)) == NULL)
+ return optional ? start : NULL;
+ return ptr;
+}
+
+/* Return the domain component of the first mailbox */
+char *
+osmtpd_mheader_from_domain(char *ptr)
+{
+ char *tmp;
+
+ /* from */
+ if (strncasecmp(ptr, "from:", 5) == 0) {
+ ptr += 5;
+ /* obs-from */
+ } else if (strncasecmp(ptr, "from", 4) == 0) {
+ ptr += 4;
+ do {
+ tmp = ptr;
+ } while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL);
+ ptr = tmp;
+ if (ptr++[0] != ':')
+ return NULL;
+ } else {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* Both from and obs-from use Mailbox-list CRLF */
+ /* obs-mbox-list has just a prefix compared to mailbox-list */
+ while (1) {
+ tmp = ptr;
+ ptr = osmtpd_mheader_skip_cfws(ptr, 1);
+ if (ptr++[0] != ',') {
+ ptr = tmp;
+ break;
+ }
+ }
+ /* We're only interested in the first mailbox */
+ if (osmtpd_mheader_skip_name_addr(ptr, 0) != NULL) {
+ ptr = osmtpd_mheader_skip_display_name(ptr, 1);
+ ptr = osmtpd_mheader_skip_cfws(ptr, 1);
+ /* < */
+ ptr++;
+ /* addr-spec */
+ ptr = osmtpd_mheader_skip_local_part(ptr, 0);
+ /* @ */
+ ptr++;
+ tmp = osmtpd_mheader_skip_domain(ptr, 0);
+ return strndup(ptr, tmp - ptr);
+ }
+ if (osmtpd_mheader_skip_addr_spec(ptr, 0) != NULL) {
+ ptr = osmtpd_mheader_skip_local_part(ptr, 0);
+ /* @ */
+ ptr++;
+ tmp = osmtpd_mheader_skip_domain(ptr, 0);
+ return strndup(ptr, tmp - ptr);
+ }
+ errno = EINVAL;
+ return NULL;
+}
blob - /dev/null
blob + 133d5dd0283a4b3a869c7aee1c189e55a74f343c (mode 644)
--- /dev/null
+++ mheader.h
+/*
+ * Copyright (c) 2020 Martijn van Duren <martijn@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.
+ */
+
+char *osmtpd_mheader_skip_sp(char *, int);
+char *osmtpd_mheader_skip_htab(char *, int);
+char *osmtpd_mheader_skip_wsp(char *, int);
+char *osmtpd_mheader_skip_crlf(char *, int);
+char *osmtpd_mheader_skip_vchar(char *, int);
+char *osmtpd_mheader_skip_lf(char *, int);
+char *osmtpd_mheader_skip_cr(char *, int);
+char *osmtpd_mheader_skip_alpha(char *, int);
+char *osmtpd_mheader_skip_digit(char *, int);
+char *osmtpd_mheader_skip_dquote(char *, int);
+char *osmtpd_mheader_skip_obs_fws(char *, int);
+char *osmtpd_mheader_skip_fws(char *, int);
+char *osmtpd_mheader_skip_obs_no_ws_ctl(char *, int);
+char *osmtpd_mheader_skip_obs_ctext(char *, int);
+char *osmtpd_mheader_skip_obs_qp(char *, int);
+char *osmtpd_mheader_skip_quoted_pair(char *, int);
+char *osmtpd_mheader_skip_ctext(char *, int);
+char *osmtpd_mheader_skip_ccontent(char *, int);
+char *osmtpd_mheader_skip_comment(char *, int);
+char *osmtpd_mheader_skip_cfws(char *, int);
+char *osmtpd_mheader_skip_atext(char *, int);
+char *osmtpd_mheader_skip_atom(char *, int);
+char *osmtpd_mheader_skip_dot_atom_text(char *, int);
+char *osmtpd_mheader_skip_dot_atom(char *, int);
+char *osmtpd_mheader_skip_obs_qtext(char *, int);
+char *osmtpd_mheader_skip_qtext(char *, int);
+char *osmtpd_mheader_skip_qcontent(char *, int);
+char *osmtpd_mheader_skip_quoted_string(char *, int);
+char *osmtpd_mheader_skip_word(char *, int);
+char *osmtpd_mheader_skip_obs_phrase(char *, int);
+char *osmtpd_mheader_skip_phrase(char *, int);
+char *osmtpd_mheader_skip_obs_local_part(char *, int);
+char *osmtpd_mheader_skip_local_part(char *, int);
+char *osmtpd_mheader_skip_obs_dtext(char *, int);
+char *osmtpd_mheader_skip_dtext(char *, int);
+char *osmtpd_mheader_skip_domain_literal(char *, int);
+char *osmtpd_mheader_skip_obs_domain(char *, int);
+char *osmtpd_mheader_skip_domain(char *, int);
+char *osmtpd_mheader_skip_display_name(char *, int);
+char *osmtpd_mheader_skip_obs_domain_list(char *, int);
+char *osmtpd_mheader_skip_obs_route(char *, int);
+char *osmtpd_mheader_skip_addr_spec(char *, int);
+char *osmtpd_mheader_skip_obs_angle_addr(char *, int);
+char *osmtpd_mheader_skip_angle_addr(char *, int);
+char *osmtpd_mheader_skip_name_addr(char *, int);
+
+char *osmtpd_mheader_from_domain(char *);