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