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