1/*++
2/* NAME
3/*	bounce_workaround 3
4/* SUMMARY
5/*	Send non-delivery notification with sender override
6/* SYNOPSIS
7/*	#include "local.h"
8/*
9/*	int	bounce_workaround(state)
10/*	LOCAL_STATE state;
11/* DESCRIPTION
12/*	This module works around a limitation in the bounce daemon
13/*	protocol, namely, the assumption that the envelope sender
14/*	address in a queue file is the delivery status notification
15/*	address for all recipients in that queue file. The assumption
16/*	is not valid when the local(8) delivery agent overrides the
17/*	envelope sender address by an owner- alias, for one or more
18/*	recipients in the queue file.
19/*
20/*	Sender address override is a problem only when delivering
21/*	to command or file, or when breaking a Delivered-To loop.
22/*	The local(8) delivery agent saves normal recipients to a
23/*	new queue file, together with the replacement envelope
24/*	sender address; delivery then proceeds from that new queue
25/*	file, and no workaround is needed.
26/*
27/*	The workaround sends one non-delivery notification for each
28/*	failed delivery that has a replacement sender address.  The
29/*	notifications are not aggregated, unlike notifications to
30/*	non-replaced sender addresses. In practice, a local alias
31/*	rarely has more than one file or command destination (if
32/*	only because soft error handling is problematic).
33/*
34/*	Arguments:
35/* .IP state
36/*	The attributes that specify the message, recipient and more.
37/*	Attributes describing alias, include or forward expansion.
38/*	A table with the results from expanding aliases or lists.
39/*	A table with delivered-to: addresses taken from the message.
40/* DIAGNOSTICS
41/*	Fatal errors: out of memory. The result is non-zero when
42/*	the operation should be tried again. Warnings: malformed
43/*	address.
44/* BUGS
45/*	The proper fix is to record in the bounce logfile an error
46/*	return address for each individual recipient. This would
47/*	eliminate the need for VERP-specific bounce protocol code,
48/*	and would move complexity from the bounce client side to
49/*	the bounce server side where it more likely belongs.
50/* LICENSE
51/* .ad
52/* .fi
53/*	The Secure Mailer license must be distributed with this
54/*	software.
55/* AUTHOR(S)
56/*	Wietse Venema
57/*	IBM T.J. Watson Research
58/*	P.O. Box 704
59/*	Yorktown Heights, NY 10598, USA
60/*--*/
61
62/* System library. */
63
64#include <sys_defs.h>
65#include <strings.h>
66
67/* Utility library. */
68
69#include <msg.h>
70#include <mymalloc.h>
71#include <vstring.h>
72#include <split_at.h>
73
74/* Global library. */
75
76#include <mail_params.h>
77#include <strip_addr.h>
78#include <stringops.h>
79#include <bounce.h>
80#include <defer.h>
81#include <split_addr.h>
82#include <canon_addr.h>
83
84/* Application-specific. */
85
86#include "local.h"
87
88int     bounce_workaround(LOCAL_STATE state)
89{
90    const char *myname = "bounce_workaround";
91    VSTRING *canon_owner = 0;
92    int     rcpt_stat;
93
94    /*
95     * Look up the substitute sender address.
96     */
97    if (var_ownreq_special) {
98	char   *stripped_recipient;
99	char   *owner_alias;
100	const char *owner_expansion;
101
102#define FIND_OWNER(lhs, rhs, addr) { \
103	lhs = concatenate("owner-", addr, (char *) 0); \
104	(void) split_at_right(lhs, '@'); \
105	rhs = maps_find(alias_maps, lhs, DICT_FLAG_NONE); \
106    }
107
108	FIND_OWNER(owner_alias, owner_expansion, state.msg_attr.rcpt.address);
109	if (alias_maps->error == 0 && owner_expansion == 0
110	    && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
111						(char **) 0,
112						var_rcpt_delim)) != 0) {
113	    myfree(owner_alias);
114	    FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
115	    myfree(stripped_recipient);
116	}
117	if (alias_maps->error == 0 && owner_expansion != 0) {
118	    canon_owner = canon_addr_internal(vstring_alloc(10),
119					      var_exp_own_alias ?
120					      owner_expansion : owner_alias);
121	    SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
122	}
123	myfree(owner_alias);
124	if (alias_maps->error != 0)
125	    /* At this point, canon_owner == 0. */
126	    return (defer_append(BOUNCE_FLAGS(state.request),
127				 BOUNCE_ATTR(state.msg_attr)));
128    }
129
130    /*
131     * Send a delivery status notification with a single recipient to the
132     * substitute sender address, before completion of the delivery request.
133     */
134    if (canon_owner) {
135	rcpt_stat = bounce_one(BOUNCE_FLAGS(state.request),
136			       BOUNCE_ONE_ATTR(state.msg_attr));
137	vstring_free(canon_owner);
138    }
139
140    /*
141     * Send a regular delivery status notification, after completion of the
142     * delivery request.
143     */
144    else {
145	rcpt_stat = bounce_append(BOUNCE_FLAGS(state.request),
146				  BOUNCE_ATTR(state.msg_attr));
147    }
148    return (rcpt_stat);
149}
150