From b7c15c31519dc44c1f691e0466badd556ffe9423 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:18:56 +0200 Subject: Adding upstream version 3.7.10. Signed-off-by: Daniel Baumann --- src/global/delivered_hdr.c | 266 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 src/global/delivered_hdr.c (limited to 'src/global/delivered_hdr.c') diff --git a/src/global/delivered_hdr.c b/src/global/delivered_hdr.c new file mode 100644 index 0000000..0aea1cc --- /dev/null +++ b/src/global/delivered_hdr.c @@ -0,0 +1,266 @@ +/*++ +/* NAME +/* delivered_hdr 3 +/* SUMMARY +/* process Delivered-To: headers +/* SYNOPSIS +/* #include +/* +/* DELIVERED_HDR_INFO *delivered_hdr_init(stream, offset, flags) +/* VSTREAM *stream; +/* off_t offset; +/* int flags; +/* +/* int delivered_hdr_find(info, address) +/* DELIVERED_HDR_INFO *info; +/* const char *address; +/* +/* void delivered_hdr_free(info) +/* DELIVERED_HDR_INFO *info; +/* DESCRIPTION +/* This module processes addresses in Delivered-To: headers. +/* These headers are added by some mail delivery systems, for the +/* purpose of breaking mail forwarding loops. N.B. This solves +/* a different problem than the Received: hop count limit. Hop +/* counts are used to limit the impact of mail routing problems. +/* +/* delivered_hdr_init() extracts Delivered-To: header addresses +/* from the specified message, and returns a table with the +/* result. The file seek pointer is changed. +/* +/* delivered_hdr_find() looks up the address in the lookup table, +/* and returns non-zero when the address was found. The +/* address argument must be in internalized form. +/* +/* delivered_hdr_free() releases storage that was allocated by +/* delivered_hdr_init(). +/* +/* Arguments: +/* .IP stream +/* The open queue file. +/* .IP offset +/* Offset of the first message content record. +/* .IP flags +/* Zero, or the bit-wise OR ot: +/* .RS +/* .IP FOLD_ADDR_USER +/* Case fold the address local part. +/* .IP FOLD_ADDR_HOST +/* Case fold the address domain part. +/* .IP FOLD_ADDR_ALL +/* Alias for (FOLD_ADDR_USER | FOLD_ADDR_HOST). +/* .RE +/* .IP info +/* Extracted Delivered-To: addresses information. +/* .IP address +/* A recipient address, internal form. +/* DIAGNOSTICS +/* Fatal errors: out of memory. +/* SEE ALSO +/* mail_copy(3), producer of Delivered-To: and other headers. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +/* System library. */ + +#include +#include +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include +#include + +/* Global library. */ + +#include +#include +#include +#include +#include +#include +#include + + /* + * Application-specific. + */ +struct DELIVERED_HDR_INFO { + int flags; + VSTRING *buf; + VSTRING *fold; + HTABLE *table; +}; + +#define STR(x) vstring_str(x) + +/* delivered_hdr_init - extract delivered-to information from the message */ + +DELIVERED_HDR_INFO *delivered_hdr_init(VSTREAM *fp, off_t offset, int flags) +{ + char *cp; + DELIVERED_HDR_INFO *info; + const HEADER_OPTS *hdr; + int curr_type; + int prev_type; + + /* + * Sanity check. + */ + info = (DELIVERED_HDR_INFO *) mymalloc(sizeof(*info)); + info->flags = flags; + info->buf = vstring_alloc(10); + info->fold = vstring_alloc(10); + info->table = htable_create(0); + + if (vstream_fseek(fp, offset, SEEK_SET) < 0) + msg_fatal("seek queue file %s: %m", VSTREAM_PATH(fp)); + + /* + * XXX Assume that mail_copy() produces delivered-to headers that fit in + * a REC_TYPE_NORM or REC_TYPE_CONT record. Lowercase the delivered-to + * addresses for consistency. + * + * XXX Don't get bogged down by gazillions of delivered-to headers. + */ +#define DELIVERED_HDR_LIMIT 1000 + + for (prev_type = REC_TYPE_NORM; + info->table->used < DELIVERED_HDR_LIMIT + && ((curr_type = rec_get(fp, info->buf, 0)) == REC_TYPE_NORM + || curr_type == REC_TYPE_CONT); + prev_type = curr_type) { + if (prev_type == REC_TYPE_CONT) + continue; + if (is_header(STR(info->buf))) { + if ((hdr = header_opts_find(STR(info->buf))) != 0 + && hdr->type == HDR_DELIVERED_TO) { + cp = STR(info->buf) + strlen(hdr->name) + 1; + while (ISSPACE(*cp)) + cp++; + cp = fold_addr(info->fold, cp, info->flags); + if (msg_verbose) + msg_info("delivered_hdr_init: %s", cp); + htable_enter(info->table, cp, (void *) 0); + } + } else if (ISSPACE(STR(info->buf)[0])) { + continue; + } else { + break; + } + } + return (info); +} + +/* delivered_hdr_find - look up recipient in delivered table */ + +int delivered_hdr_find(DELIVERED_HDR_INFO *info, const char *address) +{ + HTABLE_INFO *ht; + const char *addr_key; + + /* + * mail_copy() uses quote_822_local() when writing the Delivered-To: + * header. We must therefore apply the same transformation when looking + * up the recipient. Lowercase the delivered-to address for consistency. + */ + quote_822_local(info->buf, address); + addr_key = fold_addr(info->fold, STR(info->buf), info->flags); + ht = htable_locate(info->table, addr_key); + return (ht != 0); +} + +/* delivered_hdr_free - destructor */ + +void delivered_hdr_free(DELIVERED_HDR_INFO *info) +{ + vstring_free(info->buf); + vstring_free(info->fold); + htable_free(info->table, (void (*) (void *)) 0); + myfree((void *) info); +} + +#ifdef TEST + +#include +#include + +char *var_drop_hdrs; + +int main(int arc, char **argv) +{ + + /* + * We write test records to a VSTRING, then read with delivered_hdr_init. + */ + VSTRING *mem_bp; + VSTREAM *mem_fp; + DELIVERED_HDR_INFO *dp; + struct test_case { + int rec_type; + const char *content; + int expect_find; + }; + const struct test_case test_cases[] = { + REC_TYPE_CONT, "Delivered-To: one", 1, + REC_TYPE_NORM, "Delivered-To: two", 0, + REC_TYPE_NORM, "Delivered-To: three", 1, + 0, + }; + const struct test_case *tp; + int actual_find; + int errors; + + msg_vstream_init(argv[0], VSTREAM_ERR); + + var_drop_hdrs = mystrdup(DEF_DROP_HDRS); + + mem_bp = vstring_alloc(VSTREAM_BUFSIZE); + if ((mem_fp = vstream_memopen(mem_bp, O_WRONLY)) == 0) + msg_panic("vstream_memopen O_WRONLY failed: %m"); + +#define REC_PUT_LIT(fp, type, lit) rec_put((fp), (type), (lit), strlen(lit)) + + for (tp = test_cases; tp->content != 0; tp++) + REC_PUT_LIT(mem_fp, tp->rec_type, tp->content); + + if (vstream_fclose(mem_fp)) + msg_panic("vstream_fclose fail: %m"); + + if ((mem_fp = vstream_memopen(mem_bp, O_RDONLY)) == 0) + msg_panic("vstream_memopen O_RDONLY failed: %m"); + + dp = delivered_hdr_init(mem_fp, 0, FOLD_ADDR_ALL); + + for (errors = 0, tp = test_cases; tp->content != 0; tp++) { + actual_find = + delivered_hdr_find(dp, tp->content + sizeof("Delivered-To:")); + msg_info("test case: %c >%s<: %s (expected: %s)", + tp->rec_type, tp->content, + actual_find == tp->expect_find ? "PASS" : "FAIL", + tp->expect_find ? "MATCH" : "NO MATCH"); + errors += (actual_find != tp->expect_find);; + } + exit(errors); +} + +#endif -- cgit v1.2.3