commit 7da80e474cc43ffc4c26454ae45a58a2cdd8640a from: Kirill A. Korinsky date: Fri Jan 31 23:36:16 2025 UTC Expose iprev field 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) {