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