Commit Diff


commit - 2d73ea73b1a5ad46925c2c9ec38b4ba984b6c2db
commit + 7da80e474cc43ffc4c26454ae45a58a2cdd8640a
blob - 783c649bf34969be621d58a681bbf239da82c7cb
blob + 10c1cc66485be1a20b5b3ee2cfe6678aa2521e37
--- main.c
+++ main.c
@@ -102,6 +102,15 @@ struct dkim_signature {
 	int nqueries;
 };
 
+/*
+ * Use RFC7601 (Authentication-Results), anyway OpenSMTPD reports only pass or fail
+ */
+enum iprev_state {
+	IPREV_NONE,
+	IPREV_PASS,
+	IPREV_FAIL
+};
+
 struct header {
 	struct message *msg;
 	uint8_t readdone;
@@ -125,9 +134,17 @@ struct message {
 	int readdone;
 };
 
+struct session {
+	struct osmtpd_ctx *ctx;
+	enum iprev_state iprev;
+};
+
 void usage(void);
 void auth_conf(const char *, const char *);
+void auth_connect(struct osmtpd_ctx *, const char *, enum osmtpd_status, struct sockaddr_storage *, struct sockaddr_storage *);
 void auth_dataline(struct osmtpd_ctx *, const char *);
+void *auth_session_new(struct osmtpd_ctx *);
+void auth_session_free(struct osmtpd_ctx *, void *);
 void *auth_message_new(struct osmtpd_ctx *);
 void auth_message_free(struct osmtpd_ctx *, void *);
 void dkim_header_add(struct osmtpd_ctx *, const char *);
@@ -155,6 +172,7 @@ void dkim_header_cat(struct osmtpd_ctx *, const char *
 void dkim_body_parse(struct message *, const char *);
 void dkim_body_verify(struct dkim_signature *);
 void dkim_rr_resolve(struct asr_result *, void *);
+const char *iprev_state2str(enum iprev_state);
 void auth_message_verify(struct message *);
 ssize_t auth_ar_cat(char **ar, size_t *n, size_t aroff, const char *fmt, ...)
     __attribute__((__format__ (printf, 4, 5)));
@@ -178,8 +196,11 @@ main(int argc, char *argv[])
 	if ((ectx = EVP_ENCODE_CTX_new()) == NULL)
 		osmtpd_err(1, "EVP_ENCODE_CTX_new");
 
+	osmtpd_need(OSMTPD_NEED_FCRDNS);
 	osmtpd_register_conf(auth_conf);
 	osmtpd_register_filter_dataline(auth_dataline);
+	osmtpd_register_report_connect(1, auth_connect);
+	osmtpd_local_session(auth_session_new, auth_session_free);
 	osmtpd_local_message(auth_message_new, auth_message_free);
 	osmtpd_run();
 
@@ -206,6 +227,18 @@ auth_conf(const char *key, const char *value)
 }
 
 void
+auth_connect(struct osmtpd_ctx *ctx, const char *rdns, enum osmtpd_status fcrdns,
+			 struct sockaddr_storage *src, struct sockaddr_storage *dst)
+{
+	struct session *ses = ctx->local_session;
+
+	if (fcrdns == OSMTPD_STATUS_OK)
+		ses->iprev = IPREV_PASS;
+	else
+		ses->iprev = IPREV_FAIL;
+}
+
+void
 auth_dataline(struct osmtpd_ctx *ctx, const char *line)
 {
 	struct message *msg = ctx->local_message;
@@ -243,6 +276,28 @@ auth_dataline(struct osmtpd_ctx *ctx, const char *line
 	} else {
 		dkim_body_parse(msg, line);
 	}
+}
+
+void *
+auth_session_new(struct osmtpd_ctx *ctx)
+{
+	struct session *ses;
+
+	if ((ses = malloc(sizeof(*ses))) == NULL)
+		osmtpd_err(1, "%s: malloc", __func__);
+
+	ses->ctx = ctx;
+	ses->iprev = IPREV_NONE;
+
+	return ses;
+}
+
+void
+auth_session_free(struct osmtpd_ctx *ctx, void *data)
+{
+	struct session *ses = data;
+
+	free(ses);
 }
 
 void *
@@ -1553,11 +1608,26 @@ dkim_body_verify(struct dkim_signature *sig)
 
 	if (digestsz != sig->bhsz || memcmp(digest, sig->bh, digestsz) != 0)
 		dkim_signature_state(sig, DKIM_FAIL, "bh mismatch");
+}
+
+const char *
+iprev_state2str(enum iprev_state state)
+{
+	switch (state)
+	{
+	case IPREV_NONE:
+		return "none";
+	case IPREV_PASS:
+		return "pass";
+	case IPREV_FAIL:
+		return "fail";
+	}
 }
 
 void
 auth_message_verify(struct message *msg)
 {
+	struct session *ses = msg->ctx->local_session;
 	struct dkim_signature *sig;
 	size_t i;
 	ssize_t n, aroff = 0;
@@ -1624,6 +1694,14 @@ auth_message_verify(struct message *msg)
 		if (aroff == -1)
 			osmtpd_err(1, "%s: malloc", __func__);
 	}
+
+	if ((aroff = auth_ar_cat(&line, &linelen, aroff,
+	    "; iprev=%s", iprev_state2str(ses->iprev))) == -1)
+		osmtpd_err(1, "%s: malloc", __func__);
+
+	if (aroff == -1)
+		osmtpd_err(1, "%s: malloc", __func__);
+
 	if (auth_ar_print(msg->ctx, line) != 0) {
 		osmtpd_warnx(msg->ctx, "Mallformed AR header");
 		goto fail;
@@ -1683,6 +1761,10 @@ auth_ar_print(struct osmtpd_ctx *ctx, const char *star
 			    sizeof("dkim=") - 1) == 0) {
 				ncheckpoint = osmtpd_ltok_skip_keyword(
 				    ncheckpoint + sizeof("dkim=") - 1, 0);
+			} else if (strncmp(ncheckpoint, "iprev=",
+			    sizeof("iprev=") - 1) == 0) {
+				ncheckpoint = osmtpd_ltok_skip_keyword(
+				    ncheckpoint + sizeof("iprev=") - 1, 0);
 			/* reasonspec */
 			} else if (strncmp(ncheckpoint, "reason=",
 			    sizeof("reason=") - 1) == 0) {