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