summaryrefslogtreecommitdiffstats
path: root/src/local/bounce_workaround.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/local/bounce_workaround.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/local/bounce_workaround.c b/src/local/bounce_workaround.c
new file mode 100644
index 0000000..7fe4aaa
--- /dev/null
+++ b/src/local/bounce_workaround.c
@@ -0,0 +1,159 @@
+/*++
+/* NAME
+/* bounce_workaround 3
+/* SUMMARY
+/* Send non-delivery notification with sender override
+/* SYNOPSIS
+/* #include "local.h"
+/*
+/* int bounce_workaround(state)
+/* LOCAL_STATE state;
+/* DESCRIPTION
+/* This module works around a limitation in the bounce daemon
+/* protocol, namely, the assumption that the envelope sender
+/* address in a queue file is the delivery status notification
+/* address for all recipients in that queue file. The assumption
+/* is not valid when the local(8) delivery agent overrides the
+/* envelope sender address by an owner- alias, for one or more
+/* recipients in the queue file.
+/*
+/* Sender address override is a problem only when delivering
+/* to command or file, or when breaking a Delivered-To loop.
+/* The local(8) delivery agent saves normal recipients to a
+/* new queue file, together with the replacement envelope
+/* sender address; delivery then proceeds from that new queue
+/* file, and no workaround is needed.
+/*
+/* The workaround sends one non-delivery notification for each
+/* failed delivery that has a replacement sender address. The
+/* notifications are not aggregated, unlike notifications to
+/* non-replaced sender addresses. In practice, a local alias
+/* rarely has more than one file or command destination (if
+/* only because soft error handling is problematic).
+/*
+/* Arguments:
+/* .IP state
+/* The attributes that specify the message, recipient and more.
+/* Attributes describing alias, include or forward expansion.
+/* A table with the results from expanding aliases or lists.
+/* A table with delivered-to: addresses taken from the message.
+/* The non-delivery status must be either 4.X.X or 5.X.X.
+/* DIAGNOSTICS
+/* Fatal errors: out of memory. The result is non-zero when
+/* the operation should be tried again. Warnings: malformed
+/* address.
+/* BUGS
+/* The proper fix is to record in the bounce logfile an error
+/* return address for each individual recipient. This would
+/* eliminate the need for VERP-specific bounce protocol code,
+/* and would move complexity from the bounce client side to
+/* the bounce server side where it more likely belongs.
+/* 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
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <strings.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstring.h>
+#include <split_at.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <strip_addr.h>
+#include <stringops.h>
+#include <bounce.h>
+#include <defer.h>
+#include <split_addr.h>
+#include <canon_addr.h>
+
+/* Application-specific. */
+
+#include "local.h"
+
+int bounce_workaround(LOCAL_STATE state)
+{
+ const char *myname = "bounce_workaround";
+ VSTRING *canon_owner = 0;
+ int rcpt_stat;
+
+ /*
+ * Look up the substitute sender address.
+ */
+ if (var_ownreq_special) {
+ char *stripped_recipient;
+ char *owner_alias;
+ const char *owner_expansion;
+
+#define FIND_OWNER(lhs, rhs, addr) { \
+ lhs = concatenate("owner-", addr, (char *) 0); \
+ (void) split_at_right(lhs, '@'); \
+ rhs = maps_find(alias_maps, lhs, DICT_FLAG_NONE); \
+ }
+
+ FIND_OWNER(owner_alias, owner_expansion, state.msg_attr.rcpt.address);
+ if (alias_maps->error == 0 && owner_expansion == 0
+ && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
+ (char **) 0,
+ var_rcpt_delim)) != 0) {
+ myfree(owner_alias);
+ FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
+ myfree(stripped_recipient);
+ }
+ if (alias_maps->error == 0 && owner_expansion != 0) {
+ canon_owner = canon_addr_internal(vstring_alloc(10),
+ var_exp_own_alias ?
+ owner_expansion : owner_alias);
+ SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
+ }
+ myfree(owner_alias);
+ if (alias_maps->error != 0) {
+ /* At this point, canon_owner == 0. */
+ dsb_simple(state.msg_attr.why, "4.3.0",
+ "alias database unavailable");
+ return (defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr)));
+ }
+ }
+
+ /*
+ * Send a delivery status notification with a single recipient to the
+ * substitute sender address, before completion of the delivery request.
+ */
+ if (canon_owner) {
+ rcpt_stat =
+ (STR(state.msg_attr.why->status)[0] == '4' ?
+ defer_one : bounce_one)
+ (BOUNCE_FLAGS(state.request),
+ BOUNCE_ONE_ATTR(state.msg_attr));
+ vstring_free(canon_owner);
+ }
+
+ /*
+ * Send a regular delivery status notification, after completion of the
+ * delivery request.
+ */
+ else {
+ rcpt_stat =
+ (STR(state.msg_attr.why->status)[0] == '4' ?
+ defer_append : bounce_append)
+ (BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr));
+ }
+ return (rcpt_stat);
+}