commit 40cd76f4447b88dd8a31fe5452837b7b890ad1a7 from: Martijn van Duren date: Sun Aug 30 16:26:40 2020 UTC Add support for multiple -d flags. Needs a lot more testing. commit - 803cdd74ad2746c83be456e70b251067e2007c04 commit + 40cd76f4447b88dd8a31fe5452837b7b890ad1a7 blob - cd8936cf464c880415aeeae99c4c3de9758604e1 blob + 7e6d565348258244ea4df4c2258f1a93df024bd2 --- Makefile +++ Makefile @@ -4,7 +4,7 @@ MAN= filter-dkimsign.8 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 @@ -47,7 +47,19 @@ The canonicalization algorithm used to sign the messge 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 @@ -28,6 +28,7 @@ #include #include "opensmtpd.h" +#include "mheader.h" struct dkim_signature { char *signature; @@ -85,7 +86,8 @@ static int addtime = 0; 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; @@ -108,6 +110,7 @@ int dkim_signature_printheader(struct dkim_message *, 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 *); @@ -148,7 +151,10 @@ main(int argc, char *argv[]) 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); @@ -279,11 +285,10 @@ dkim_message_new(struct osmtpd_ctx *ctx) 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; @@ -532,6 +537,7 @@ dkim_sign(struct osmtpd_ctx *ctx) 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; @@ -569,6 +575,8 @@ dkim_sign(struct osmtpd_ctx *ctx) 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') @@ -581,7 +589,7 @@ dkim_sign(struct osmtpd_ctx *ctx) 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) { @@ -777,6 +785,34 @@ dkim_signature_printf(struct dkim_message *message, ch 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 @@ -0,0 +1,682 @@ +/* + * Copyright (c) 2020 Martijn van Duren + * + * 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 "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 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 Martijn van Duren + * + * 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 *);