commit - e9e8d2076ab3dc31d76955739dc0afb9f32888c0
commit + 4f29629bac17e2bc8fec298499946fd7518d249e
blob - eaa019c9175a22f22b80db9c87f1b9a4854d5407
blob + b1de9767ec30f0862521244246bb8070080eaf9c
--- 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 - e419f50f5abc33db2762639e83baa6c79b509bd5
blob + 3bdfa0acc2e91c50c8f38f9078d9efa9a81251d9
--- filter-admdscrub.8
+++ filter-admdscrub.8
.Sh SYNOPSIS
.Nm
.Op Fl rv
-.Op Fl a Ar authserv-id
+.Op Ar authserv-id
.Sh DESCRIPTION
.Nm
checks the mail for
blob - 2bd64da3091101695ecc4fdf97d4c70f4546d557
blob + 1f776bcb78fb44859e4b8b7ad9b91cefa9e09c8a
--- main.c
+++ main.c
#include <unistd.h>
#include "opensmtpd.h"
+#include "mheader.h"
struct admd_message {
int foundmatch;
int parsing_headers;
char **cache;
size_t cachelen;
+ size_t headerlen;
};
void usage(void);
const char *admd_authservid(struct admd_message *);
void admd_freecache(struct admd_message *);
-char authservid[256] = "";
+char authservid[256];
int reject = 0;
int verbose = 0;
{
int ch;
- while ((ch = getopt(argc, argv, "a:rv")) != -1) {
+ if (pledge("stdio", NULL) == -1)
+ osmtpd_err(1, "pledge");
+
+ while ((ch = getopt(argc, argv, "rv")) != -1) {
switch (ch) {
- case 'a':
- if (strlcpy(authservid, optarg, sizeof(authservid)) >=
- sizeof(authservid))
- osmtpd_errx(1, "authserv-id is too long");
- break;
case 'r':
reject = 1;
break;
usage();
}
}
-
- if (pledge("stdio", NULL) == -1)
- osmtpd_err(1, "pledge");
-
- if (authservid[0] == '\0') {
+ argc -= optind;
+ argv += optind;
+ if (argc > 1)
+ osmtpd_errx(1, "invalid authservid count");
+ if (argc == 1) {
+ if (strlcpy(authservid, argv[0], sizeof(authservid)) >=
+ sizeof(authservid))
+ osmtpd_errx(1, "authserv-id is too long");
+ } else {
if (gethostname(authservid, sizeof(authservid)) == -1)
osmtpd_err(1, "gethostname");
}
msg->parsing_headers = 1;
msg->cache = NULL;
msg->cachelen = 0;
+ msg->headerlen = 0;
return msg;
}
if (line[0] != ' ' && line[0] != '\t') {
if (msg->inheader) {
msgauthid = admd_authservid(msg);
- if (strcmp(msgauthid, authservid) == 0)
+ if (msgauthid == NULL && errno != EINVAL)
+ return;
+ if (msgauthid != NULL &&
+ strcmp(msgauthid, authservid) == 0)
msg->foundmatch = 1;
else {
for (i = 0; i < msg->cachelen; i++)
}
msg->inheader = 0;
}
- if (strncmp(line, "Authentication-Results:", 23) == 0) {
- msg->inheader = 1;
- admd_cache(msg, orig);
- return;
- }
- if (msg->inheader && (line[0] == ' ' || line[0] == '\t')) {
+ if (strncasecmp(line, "Authentication-Results", 22) == 0) {
+ line += 22;
+ while (line[0] == ' ' || line[0] == '\t')
+ line++;
+ if (line++[0] == ':') {
+ msg->inheader = 1;
+ admd_cache(msg, orig);
+ return;
+ }
+ } else if (msg->inheader &&
+ (line[0] == ' ' || line[0] == '\t')) {
admd_cache(msg, orig);
return;
}
admd_err(msg, "strdup");
}
msg->cachelen++;
+ msg->headerlen += strlen(line[0] == '.' ? line + 1 : line);
return;
}
const char *
admd_authservid(struct admd_message *msg)
{
- static char msgauthid[sizeof(authservid)];
- const char *header;
+ char *header0, *header, *line, *end;
+ size_t headerlen;
size_t i = 0;
- int depth = 0;
- msgauthid[0] = '\0';
+ headerlen = msg->headerlen + (msg->cachelen * 2) + 1;
+ header0 = header = malloc(headerlen);
+ if (header == NULL) {
+ admd_err(msg, "malloc");
+ return NULL;
+ }
+ header[0] = '\0';
+ for (i = 0; i < msg->cachelen; i++) {
+ line = msg->cache[i];
+ if (line[0] == '.')
+ line++;
+ if (strlcat(header, line, headerlen) >= headerlen ||
+ strlcat(header, "\r\n", headerlen) >= headerlen) {
+ osmtpd_errx(1, "miscalculated header\n");
+ exit(1);
+ }
+ }
- header = msg->cache[0];
-
- if (header[0] == '.')
- header++;
-
/* Skip key */
- header += 23;
-
- /* CFWS */
- /*
- * Take the extremely loose approach with both FWS and comment so we
- * might match a non fully complient comment and still get the right
- * authserv-id
- */
-fws:
+ header += 22;
while (header[0] == ' ' || header[0] == '\t')
header++;
- if (header[0] == '\0') {
- if (++i >= msg->cachelen)
- return msgauthid;
- header = msg->cache[i];
- /* For leniency allow multiple consequtive FWS */
- goto fws;
+ /* : */
+ header++;
+
+ header = osmtpd_mheader_skip_cfws(header, 1);
+
+ if ((end = osmtpd_mheader_skip_value(header, 0)) == NULL) {
+ errno = EINVAL;
+ free(header0);
+ return NULL;
}
- /* comment */
- if (header[0] == '(') {
- depth++;
- header++;
- }
- if (depth > 0) {
- while (1) {
- /*
- * consume a full quoted-pair, which may contain
- * parentheses
- */
- if (header[0] == '"') {
- header++;
- while (header[0] != '"') {
- if (header[0] == '\\')
- header++;
- if (header[0] == '\0') {
- if (++i >= msg->cachelen) {
- return msgauthid;
- }
- header = msg->cache[i];
- } else
- header++;
- }
- header++;
- /* End of comment */
- } else if (header[0] == ')') {
- header++;
- if (--depth == 0)
- goto fws;
- } else if (header[0] == '(') {
- header++;
- depth++;
- } else if (header[0] == '\0') {
- if (++i >= msg->cachelen)
- return msgauthid;
- header = msg->cache[i];
- } else
- header++;
- }
- }
- /* Quoted-string */
- if (header[0] == '"') {
- header++;
- for (i = 0; header[0] != '"' && header[0] != '\0' &&
- i < sizeof(msgauthid); i++, header++) {
- if (header[0] == '\\')
- header++;
- /* Don't do Newline at all */
- if (header[0] == '\0') {
- i = 0;
- break;
- }
- msgauthid[i] = header[0];
- }
- /* token */
- } else {
- /*
- * Be more lenient towards token to hit more
- * edgecases
- */
- for (i = 0; header[i] != ' ' && header[i] != '\t' &&
- header[i] != ';' && header[i] != '\0' &&
- i < sizeof(msgauthid); i++)
- msgauthid[i] = header[i];
- }
- /* If we overflow we simply don't match */
- if (i == sizeof(msgauthid))
- i = 0;
- msgauthid[i] = '\0';
- return msgauthid;
+ memmove(header0, header, end - header);
+ header0[end - header] = '\0';
+
+ return header0;
}
void
free(msg->cache);
msg->cache = NULL;
msg->cachelen = 0;
+ msg->headerlen = 0;
}
__dead void
blob - /dev/null
blob + 8831ab8037ae6aa8869bb840ff8f92295b0ee930 (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_char(char *ptr, int optional)
+{
+ if (ptr[0] >= 0x1 && ptr[0] <= 0x7f)
+ return ptr + 1;
+ return optional ? ptr : NULL;
+}
+
+char *
+osmtpd_mheader_skip_ctl(char *ptr, int optional)
+{
+ if ((ptr[0] >= 0x0 && ptr[0] <= 0x1f) || ptr[0] == 0x7f)
+ 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;
+}
+
+/* RFC 2045 */
+char *
+osmtpd_mheader_skip_tspecials(char *ptr, int optional)
+{
+ 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] == '=')
+ return ptr + 1;
+ return optional ? ptr : NULL;
+
+}
+
+char *
+osmtpd_mheader_skip_token(char *ptr, int optional)
+{
+ if (osmtpd_mheader_skip_char(ptr, 0) == NULL)
+ return optional ? ptr : NULL;
+ /* Can't find the official definition for SPACE, so use WSP */
+ if (osmtpd_mheader_skip_wsp(ptr, 0) != NULL)
+ return optional ? ptr : NULL;
+ if (osmtpd_mheader_skip_ctl(ptr, 0) != NULL)
+ return optional ? ptr : NULL;
+ if (osmtpd_mheader_skip_tspecials(ptr, 0) != NULL)
+ return optional ? ptr : NULL;
+ ptr++;
+ while (1) {
+ if (osmtpd_mheader_skip_char(ptr, 0) == NULL)
+ return ptr;
+ if (osmtpd_mheader_skip_wsp(ptr, 0) != NULL)
+ return ptr;
+ if (osmtpd_mheader_skip_ctl(ptr, 0) != NULL)
+ return ptr;
+ if (osmtpd_mheader_skip_tspecials(ptr, 0) != NULL)
+ return ptr;
+ ptr++;
+ }
+}
+
+char *
+osmtpd_mheader_skip_value(char *ptr, int optional)
+{
+ char *start = ptr;
+
+ if ((ptr = osmtpd_mheader_skip_token(ptr, 0)) == NULL)
+ return osmtpd_mheader_skip_quoted_string(start, optional);
+ 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 + afc337958a16e8ba85c5144bf9edeacd225e18b5 (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_char(char *, int);
+char *osmtpd_mheader_skip_ctl(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_skip_tspecials(char *, int);
+char *osmtpd_mheader_skip_token(char *, int);
+char *osmtpd_mheader_skip_value(char *, int);
+
+char *osmtpd_mheader_from_domain(char *);