Commit Diff


commit - e974922c653d65bd532e1dc385cf9e479aa4f38f
commit + c826412d86123fb2346635710aabec82f8e33946
blob - 28d8ba5bf82eb2649a65a0eac8506ad50819861c
blob + 114ca8bc90f950566cfe35bb43c14ae1b58834c9
--- filter-dkim.1
+++ filter-dkim.1
@@ -27,6 +27,8 @@
 .Op Fl h Ar headers
 .Op Fl t
 .Op Fl x Ar seconds
+.Op Fl z
+.Op Fl Z
 .Fl d Ar domain
 .Fl k Ar file
 .Fl s Ar selector
@@ -67,6 +69,12 @@ Add the time of signing to the dkim header.
 Add the amount of
 .Ar seconds
 the signature is valid to the dkim header.
+.It Fl z
+Add the mail headers used in the dkim signature to the dkim header.
+Useful for debugging purposes.
+.It Fl Z
+Add all the mail headers to the dkim header.
+Useful for debugging purposes.
 .El
 .Sh SEE ALSO
 .Xr smtpd 8
blob - 3cea23ed9ce4523d9d36321b860f6531d5554eec
blob + be71a9bd0e73e19d1841154579e31e506362fa4e
--- main.c
+++ main.c
@@ -21,6 +21,7 @@
 
 #include <ctype.h>
 #include <err.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -92,6 +93,7 @@ static int canonbody = CANON_SIMPLE;
 
 static int addtime = 0;
 static long long addexpire = 0;
+static int addheaders = 0;
 
 static char *domain = NULL;
 static char *selector = NULL;
@@ -116,6 +118,7 @@ int dkim_session_cmp(struct dkim_session *, struct dki
 void dkim_parse_header(struct dkim_session *, char *, int);
 void dkim_parse_body(struct dkim_session *, char *);
 void dkim_sign(struct dkim_session *);
+int dkim_signature_printheader(struct dkim_session *, char *);
 int dkim_signature_printf(struct dkim_session *, char *, ...)
 	__attribute__((__format__ (printf, 2, 3)));
 int dkim_signature_normalize(struct dkim_session *);
@@ -131,7 +134,7 @@ main(int argc, char *argv[])
 	FILE *keyfile;
 	const char *errstr;
 
-	while ((ch = getopt(argc, argv, "a:c:Dd:h:k:s:tx:")) != -1) {
+	while ((ch = getopt(argc, argv, "a:c:Dd:h:k:s:tx:zZ")) != -1) {
 		switch (ch) {
 		case 'a':
 			if (strncmp(optarg, "rsa-", 4) != 0)
@@ -186,6 +189,12 @@ main(int argc, char *argv[])
 			if (addexpire == 0)
 				errx(1, "Expire offset is %s", errstr);
 			break;
+		case 'z':
+			addheaders = 1;
+			break;
+		case 'Z':
+			addheaders = 2;
+			break;
 		case 'D':
 			debug = 1;
 			break;
@@ -257,6 +266,8 @@ dkim_dataline(char *type, int version, struct timespec
 			line++;
 		dkim_parse_header(session, line, 0);
 	} else if (linelen == 0 && session->parsing_headers) {
+		if (addheaders > 0 && !dkim_signature_printf(session, "; "))
+			return;
 		session->parsing_headers = 0;
 	} else {
 		if (line[0] == '.')
@@ -319,6 +330,8 @@ dkim_session_new(uint64_t reqid)
 	    canonbody == CANON_SIMPLE ? "simple" : "relaxed",
 	    domain, selector))
 		return NULL;
+	if (addheaders > 0 && !dkim_signature_printf(session, "z="))
+		return NULL;
 
 	if ((session->b = EVP_MD_CTX_new()) == NULL ||
 	    (session->bh = EVP_MD_CTX_new()) == NULL) {
@@ -424,6 +437,10 @@ dkim_parse_header(struct dkim_session *session, char *
 	char *htmp;
 	char *tmp;
 
+	if (addheaders == 2 && !force &&
+	    !dkim_signature_printheader(session, line))
+		return;
+
 	if ((line[0] == ' ' || line[0] == '\t') && !session->lastheader)
 		return;
 	if ((line[0] != ' ' && line[0] != '\t')) {
@@ -442,6 +459,10 @@ dkim_parse_header(struct dkim_session *session, char *
 			return;
 	}
 
+	if (addheaders == 1 && !force &&
+	    !dkim_signature_printheader(session, line))
+		return;
+
 	if (canonheader == CANON_RELAXED) {
 		if (!session->lastheader)
 			fieldname = 1;
@@ -724,11 +745,13 @@ dkim_signature_normalize(struct dkim_session *session)
 		switch (tag) {
 		case 'B':
 		case 'b':
+		case 'z':
 			checkpoint = i;
 			break;
 		case 'h':
 			if (sig[i] == ':')
 				checkpoint = i;
+			break;
 		}
 		if (tag == '\0' && sig[i] != ' ' && sig[i] != '\t') {
 			if ((tag = sig[i]) == 'b' && sig[i + 1] == 'h' &&
@@ -744,6 +767,51 @@ dkim_signature_normalize(struct dkim_session *session)
 }
 
 int
+dkim_signature_printheader(struct dkim_session *session, char *header)
+{
+	size_t i, j, len;
+	static char *fmtheader = NULL;
+	char *tmp;
+	static size_t size = 0;
+	int first;
+
+	len = strlen(header);
+	if ((len + 3) * 3 < len) {
+		errno = EOVERFLOW;
+		dkim_err(session, "Can't add z-component to header");
+		return 0;
+	}
+	if ((len + 3) * 3 > size) {
+		if ((tmp = reallocarray(fmtheader, 3, len + 3)) == NULL) {
+			dkim_err(session, "Can't add z-component to header");
+			return 0;
+		}
+		fmtheader = tmp;
+		size = (len + 1) * 3;
+	}
+
+	first = session->signature.signature[session->signature.len - 1] == '=';
+	for (j = i = 0; header[i] != '\0'; i++, j++) {
+		if (i == 0 && header[i] != ' ' && header[i] != '\t' && !first)
+			fmtheader[j++] = '|';
+		if ((header[i] >= 0x21 && header[i] <= 0x3A) ||
+		     header[i] == 0x3C ||
+		    (header[i] >= 0x3E && header[i] <= 0x7B) ||
+		    (header[i] >= 0x7D && header[i] <= 0x7E))
+			fmtheader[j] = header[i];
+		else {
+			fmtheader[j++] = '=';
+			(void) sprintf(fmtheader + j, "%02hhX", header[i]);
+			j++;
+		}
+	}
+	(void) sprintf(fmtheader + j, "=%02hhX=%02hhX", (unsigned char) '\r',
+	    (unsigned char) '\n');
+
+	return dkim_signature_printf(session, "%s", fmtheader);
+}
+
+int
 dkim_signature_printf(struct dkim_session *session, char *fmt, ...)
 {
 	struct dkim_signature *sig = &(session->signature);