1/*++ 2/* NAME 3/* cleanup_out_recipient 3 4/* SUMMARY 5/* envelope recipient output filter 6/* SYNOPSIS 7/* #include "cleanup.h" 8/* 9/* void cleanup_out_recipient(state, dsn_orig_recipient, 10/* dsn_notify, orig_recipient, 11/* recipient) 12/* CLEANUP_STATE *state; 13/* const char *dsn_orig_recipient; 14/* const char *dsn_notify; 15/* const char *orig_recipient; 16/* const char *recipient; 17/* DESCRIPTION 18/* This module implements an envelope recipient output filter. 19/* 20/* cleanup_out_recipient() performs virtual table expansion 21/* and recipient duplicate filtering, and appends the 22/* resulting recipients to the output stream. It also 23/* generates DSN SUCCESS notifications. 24/* 25/* Arguments: 26/* .IP state 27/* Cleanup server state. 28/* .IP dsn_orig_recipient 29/* DSN original recipient information. 30/* .IP dsn_notify 31/* DSN notify flags. 32/* .IP orig_recipient 33/* Envelope recipient as received by Postfix. 34/* .IP recipient 35/* Envelope recipient as rewritten by Postfix. 36/* CONFIGURATION 37/* .ad 38/* .fi 39/* .IP enable_original_recipient 40/* Enable orig_recipient support. 41/* .IP local_duplicate_filter_limit 42/* Upper bound to the size of the recipient duplicate filter. 43/* Zero means no limit; this may cause the mail system to 44/* become stuck. 45/* .IP virtual_alias_maps 46/* list of virtual address lookup tables. 47/* LICENSE 48/* .ad 49/* .fi 50/* The Secure Mailer license must be distributed with this software. 51/* AUTHOR(S) 52/* Wietse Venema 53/* IBM T.J. Watson Research 54/* P.O. Box 704 55/* Yorktown Heights, NY 10598, USA 56/*--*/ 57 58/* System library. */ 59 60#include <sys_defs.h> 61#include <string.h> 62 63/* Utility library. */ 64 65#include <argv.h> 66#include <msg.h> 67 68/* Global library. */ 69 70#include <been_here.h> 71#include <mail_params.h> 72#include <rec_type.h> 73#include <ext_prop.h> 74#include <cleanup_user.h> 75#include <dsn_mask.h> 76#include <recipient_list.h> 77#include <dsn.h> 78#include <trace.h> 79#include <mail_queue.h> /* cleanup_trace_path */ 80#include <mail_proto.h> 81#include <msg_stats.h> 82 83/* Application-specific. */ 84 85#include "cleanup.h" 86 87/* cleanup_trace_append - update trace logfile */ 88 89static void cleanup_trace_append(CLEANUP_STATE *state, RECIPIENT *rcpt, 90 DSN *dsn) 91{ 92 MSG_STATS stats; 93 94 if (cleanup_trace_path == 0) { 95 cleanup_trace_path = vstring_alloc(10); 96 mail_queue_path(cleanup_trace_path, MAIL_QUEUE_TRACE, 97 state->queue_id); 98 } 99 if (trace_append(BOUNCE_FLAG_CLEAN, state->queue_id, 100 CLEANUP_MSG_STATS(&stats, state), 101 rcpt, "none", dsn) != 0) { 102 msg_warn("%s: trace logfile update error", state->queue_id); 103 state->errs |= CLEANUP_STAT_WRITE; 104 } 105} 106 107/* cleanup_out_recipient - envelope recipient output filter */ 108 109void cleanup_out_recipient(CLEANUP_STATE *state, 110 const char *dsn_orcpt, 111 int dsn_notify, 112 const char *orcpt, 113 const char *recip) 114{ 115 ARGV *argv; 116 char **cpp; 117 118 /* 119 * XXX Not elegant, but eliminates complexity in the record reading loop. 120 */ 121 if (!var_enable_orcpt) 122 orcpt = ""; 123 if (dsn_orcpt == 0) 124 dsn_orcpt = ""; 125 126 /* 127 * Distinguish between different original recipient addresses that map 128 * onto the same mailbox. The recipient will use our original recipient 129 * message header to figure things out. 130 * 131 * Postfix 2.2 compatibility: when ignoring differences in Postfix original 132 * recipient information, also ignore differences in DSN attributes. We 133 * do, however, keep the DSN attributes of the recipient that survives 134 * duplicate elimination. 135 */ 136#define STREQ(x, y) (strcmp((x), (y)) == 0) 137 138 if ((state->flags & CLEANUP_FLAG_MAP_OK) == 0 139 || cleanup_virt_alias_maps == 0) { 140 if ((var_enable_orcpt ? 141 been_here(state->dups, "%s\n%d\n%s\n%s", 142 dsn_orcpt, dsn_notify, orcpt, recip) : 143 been_here_fixed(state->dups, recip)) == 0) { 144 if (dsn_notify) 145 cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d", 146 MAIL_ATTR_DSN_NOTIFY, dsn_notify); 147 if (*dsn_orcpt) 148 cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s", 149 MAIL_ATTR_DSN_ORCPT, dsn_orcpt); 150 cleanup_out_string(state, REC_TYPE_ORCP, orcpt); 151 cleanup_out_string(state, REC_TYPE_RCPT, recip); 152 state->rcpt_count++; 153 } 154 } 155 156 /* 157 * XXX DSN. RFC 3461 gives us three options for multi-recipient aliases 158 * (we're treating single recipient aliases as a special case of 159 * multi-recipient aliases, one argument being that it is none of the 160 * sender's business). 161 * 162 * (a) Don't propagate ENVID, NOTIFY, RET, or ORCPT. If NOTIFY specified 163 * SUCCESS, send a "relayed" DSN. 164 * 165 * (b) Propagate ENVID, (NOTIFY minus SUCCESS), RET, and ORCPT. If NOTIFY 166 * specified SUCCESS, send an "expanded" DSN. 167 * 168 * (c) Propagate ENVID, NOTIFY, RET, and ORCPT to one recipient only. Send 169 * no DSN. 170 * 171 * In all three cases we are modifying at least one NOTIFY value. Either we 172 * have to record explicit dsn_notify records, or we must not allow the 173 * use of a per-message non-default NOTIFY value that applies to all 174 * recipient records. 175 * 176 * Alternatives (a) and (c) require that we store explicit per-recipient RET 177 * and ENVID records, at least for the recipients that are excluded from 178 * RET and ENVID propagation. This means storing explicit ENVID records 179 * to indicate that the information does not exist. All this makes 180 * alternative (b) more and more attractive. It is no surprise that we 181 * use (b) here and in the local delivery agent. 182 * 183 * In order to generate a SUCCESS notification from the cleanup server we 184 * have to write the trace logfile record now. We're NOT going to flush 185 * the trace file from the cleanup server; if we need to write bounce 186 * logfile records, and the bounce service fails, we must be able to 187 * cancel the entire cleanup request including any success or failure 188 * notifications. The queue manager will flush the trace (and bounce) 189 * logfile, possibly after it has generated its own success or failure 190 * notification records. 191 * 192 * Postfix 2.2 compatibility: when ignoring differences in Postfix original 193 * recipient information, also ignore differences in DSN attributes. We 194 * do, however, keep the DSN attributes of the recipient that survives 195 * duplicate elimination. 196 */ 197 else { 198 RECIPIENT rcpt; 199 DSN dsn; 200 201 argv = cleanup_map1n_internal(state, recip, cleanup_virt_alias_maps, 202 cleanup_ext_prop_mask & EXT_PROP_VIRTUAL); 203 if ((dsn_notify & DSN_NOTIFY_SUCCESS) 204 && (argv->argc > 1 || strcmp(recip, argv->argv[0]) != 0)) { 205 (void) DSN_SIMPLE(&dsn, "2.0.0", "alias expanded"); 206 dsn.action = "expanded"; 207 RECIPIENT_ASSIGN(&rcpt, 0, dsn_orcpt, dsn_notify, orcpt, recip); 208 cleanup_trace_append(state, &rcpt, &dsn); 209 dsn_notify = (dsn_notify == DSN_NOTIFY_SUCCESS ? DSN_NOTIFY_NEVER : 210 dsn_notify & ~DSN_NOTIFY_SUCCESS); 211 } 212 for (cpp = argv->argv; *cpp; cpp++) { 213 if ((var_enable_orcpt ? 214 been_here(state->dups, "%s\n%d\n%s\n%s", 215 dsn_orcpt, dsn_notify, orcpt, *cpp) : 216 been_here_fixed(state->dups, *cpp)) == 0) { 217 if (dsn_notify) 218 cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d", 219 MAIL_ATTR_DSN_NOTIFY, dsn_notify); 220 if (*dsn_orcpt) 221 cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s", 222 MAIL_ATTR_DSN_ORCPT, dsn_orcpt); 223 cleanup_out_string(state, REC_TYPE_ORCP, orcpt); 224 cleanup_out_string(state, REC_TYPE_RCPT, *cpp); 225 state->rcpt_count++; 226 } 227 } 228 argv_free(argv); 229 } 230} 231