1 /* $NetBSD: cleanup_addr.c,v 1.2 2017/02/14 01:16:44 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* cleanup_addr 3 6 /* SUMMARY 7 /* process envelope addresses 8 /* SYNOPSIS 9 /* #include <cleanup.h> 10 /* 11 /* off_t cleanup_addr_sender(state, addr) 12 /* CLEANUP_STATE *state; 13 /* const char *addr; 14 /* 15 /* void cleanup_addr_recipient(state, addr) 16 /* CLEANUP_STATE *state; 17 /* const char *addr; 18 /* 19 /* void cleanup_addr_bcc_dsn(state, addr, dsn_orcpt, dsn_notify) 20 /* CLEANUP_STATE *state; 21 /* const char *addr; 22 /* const char *dsn_orcpt; 23 /* int dsn_notify; 24 /* 25 /* void cleanup_addr_bcc(state, addr) 26 /* CLEANUP_STATE *state; 27 /* const char *addr; 28 /* DESCRIPTION 29 /* This module processes envelope address records and writes the result 30 /* to the queue file. Processing includes address rewriting and 31 /* sender/recipient auto bcc address generation. 32 /* 33 /* cleanup_addr_sender() processes sender envelope information and updates 34 /* state->sender. The result value is the offset of the record that 35 /* follows the sender record if milters are enabled, otherwise zero. 36 /* 37 /* cleanup_addr_recipient() processes recipient envelope information 38 /* and updates state->recip. 39 /* 40 /* cleanup_addr_bcc_dsn() processes recipient envelope information. This 41 /* is a separate function to avoid invoking cleanup_addr_recipient() 42 /* recursively. 43 /* 44 /* cleanup_addr_bcc() is a backwards-compatibility wrapper for 45 /* cleanup_addr_bcc_dsn() that requests no delivery status 46 /* notification for the recipient. 47 /* 48 /* Arguments: 49 /* .IP state 50 /* Queue file and message processing state. This state is updated 51 /* as records are processed and as errors happen. 52 /* .IP buf 53 /* Record content. 54 /* .IP dsn_orcpt 55 /* The DSN original recipient (or NO_DSN_ORCPT to specify none). 56 /* .IP dsn_notify 57 /* DSN notification options. Specify NO_DSN_NOTIFY to disable 58 /* notification, and DEF_DSN_NOTIFY for default notification. 59 /* LICENSE 60 /* .ad 61 /* .fi 62 /* The Secure Mailer license must be distributed with this software. 63 /* AUTHOR(S) 64 /* Wietse Venema 65 /* IBM T.J. Watson Research 66 /* P.O. Box 704 67 /* Yorktown Heights, NY 10598, USA 68 /*--*/ 69 70 /* System library. */ 71 72 #include <sys_defs.h> 73 #include <string.h> 74 #include <stdlib.h> 75 76 /* Utility library. */ 77 78 #include <msg.h> 79 #include <vstring.h> 80 #include <vstream.h> 81 #include <mymalloc.h> 82 #include <stringops.h> 83 84 /* Global library. */ 85 86 #include <rec_type.h> 87 #include <record.h> 88 #include <cleanup_user.h> 89 #include <mail_params.h> 90 #include <ext_prop.h> 91 #include <mail_addr.h> 92 #include <canon_addr.h> 93 #include <mail_addr_find.h> 94 #include <mail_proto.h> 95 #include <dsn_mask.h> 96 #include <smtputf8.h> 97 98 /* Application-specific. */ 99 100 #include "cleanup.h" 101 102 #define STR vstring_str 103 #define LEN VSTRING_LEN 104 #define IGNORE_EXTENSION (char **) 0 105 106 /* cleanup_addr_sender - process envelope sender record */ 107 108 off_t cleanup_addr_sender(CLEANUP_STATE *state, const char *buf) 109 { 110 const char myname[] = "cleanup_addr_sender"; 111 VSTRING *clean_addr = vstring_alloc(100); 112 off_t after_sender_offs = 0; 113 const char *bcc; 114 size_t len; 115 116 /* 117 * Note: an unqualified envelope address is for all practical purposes 118 * equivalent to a fully qualified local address, both for delivery and 119 * for replying. Having to support both forms is error prone, therefore 120 * an incomplete envelope address is rewritten to fully qualified form in 121 * the local domain context. 122 * 123 * 20000520: Replace mailer-daemon@$myorigin by the null address, to handle 124 * bounced mail traffic more robustly. 125 */ 126 cleanup_rewrite_internal(MAIL_ATTR_RWR_LOCAL, clean_addr, buf); 127 if (strncasecmp_utf8(STR(clean_addr), MAIL_ADDR_MAIL_DAEMON "@", 128 sizeof(MAIL_ADDR_MAIL_DAEMON)) == 0) { 129 canon_addr_internal(state->temp1, MAIL_ADDR_MAIL_DAEMON); 130 if (strcasecmp_utf8(STR(clean_addr), STR(state->temp1)) == 0) 131 vstring_strcpy(clean_addr, ""); 132 } 133 if (state->flags & CLEANUP_FLAG_MAP_OK) { 134 if (cleanup_send_canon_maps 135 && (cleanup_send_canon_flags & CLEANUP_CANON_FLAG_ENV_FROM)) 136 cleanup_map11_internal(state, clean_addr, cleanup_send_canon_maps, 137 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 138 if (cleanup_comm_canon_maps 139 && (cleanup_comm_canon_flags & CLEANUP_CANON_FLAG_ENV_FROM)) 140 cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps, 141 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 142 if (cleanup_masq_domains 143 && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_FROM)) 144 cleanup_masquerade_internal(state, clean_addr, cleanup_masq_domains); 145 } 146 /* Fix 20140711: Auto-detect an UTF8 sender. */ 147 if (var_smtputf8_enable && *STR(clean_addr) && !allascii(STR(clean_addr)) 148 && valid_utf8_string(STR(clean_addr), LEN(clean_addr))) { 149 state->smtputf8 |= SMTPUTF8_FLAG_SENDER; 150 /* Fix 20140713: request SMTPUTF8 support selectively. */ 151 if (state->flags & CLEANUP_FLAG_AUTOUTF8) 152 state->smtputf8 |= SMTPUTF8_FLAG_REQUESTED; 153 } 154 CLEANUP_OUT_BUF(state, REC_TYPE_FROM, clean_addr); 155 if (state->sender) /* XXX Can't happen */ 156 myfree(state->sender); 157 state->sender = mystrdup(STR(clean_addr)); /* Used by Milter client */ 158 /* Fix 20160310: Moved from cleanup_envelope.c. */ 159 if (state->milters || cleanup_milters) { 160 /* Make room to replace sender. */ 161 if ((len = LEN(clean_addr)) < REC_TYPE_PTR_PAYL_SIZE) 162 rec_pad(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_PAYL_SIZE - len); 163 /* Remember the after-sender record offset. */ 164 if ((after_sender_offs = vstream_ftell(state->dst)) < 0) 165 msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path); 166 } 167 if ((state->flags & CLEANUP_FLAG_BCC_OK) 168 && *STR(clean_addr) 169 && cleanup_send_bcc_maps) { 170 if ((bcc = mail_addr_find(cleanup_send_bcc_maps, STR(clean_addr), 171 IGNORE_EXTENSION)) != 0) { 172 cleanup_addr_bcc(state, bcc); 173 } else if (cleanup_send_bcc_maps->error) { 174 msg_warn("%s: %s map lookup problem -- " 175 "message not accepted, try again later", 176 state->queue_id, cleanup_send_bcc_maps->title); 177 state->errs |= CLEANUP_STAT_WRITE; 178 } 179 } 180 vstring_free(clean_addr); 181 return after_sender_offs; 182 } 183 184 /* cleanup_addr_recipient - process envelope recipient */ 185 186 void cleanup_addr_recipient(CLEANUP_STATE *state, const char *buf) 187 { 188 VSTRING *clean_addr = vstring_alloc(100); 189 const char *bcc; 190 191 /* 192 * Note: an unqualified envelope address is for all practical purposes 193 * equivalent to a fully qualified local address, both for delivery and 194 * for replying. Having to support both forms is error prone, therefore 195 * an incomplete envelope address is rewritten to fully qualified form in 196 * the local domain context. 197 */ 198 cleanup_rewrite_internal(MAIL_ATTR_RWR_LOCAL, 199 clean_addr, *buf ? buf : var_empty_addr); 200 if (state->flags & CLEANUP_FLAG_MAP_OK) { 201 if (cleanup_rcpt_canon_maps 202 && (cleanup_rcpt_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT)) 203 cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps, 204 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 205 if (cleanup_comm_canon_maps 206 && (cleanup_comm_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT)) 207 cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps, 208 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 209 if (cleanup_masq_domains 210 && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT)) 211 cleanup_masquerade_internal(state, clean_addr, cleanup_masq_domains); 212 } 213 /* Fix 20140711: Auto-detect an UTF8 recipient. */ 214 if (var_smtputf8_enable && *STR(clean_addr) && !allascii(STR(clean_addr)) 215 && valid_utf8_string(STR(clean_addr), LEN(clean_addr))) { 216 /* Fix 20140713: request SMTPUTF8 support selectively. */ 217 if (state->flags & CLEANUP_FLAG_AUTOUTF8) 218 state->smtputf8 |= SMTPUTF8_FLAG_REQUESTED; 219 } 220 /* Fix 20141024: Don't fake up a "bare" DSN original rcpt in smtp(8). */ 221 if (state->dsn_orcpt == 0 && *STR(clean_addr) != 0) 222 state->dsn_orcpt = concatenate((!allascii(STR(clean_addr)) 223 && (state->smtputf8 & SMTPUTF8_FLAG_REQUESTED)) ? 224 "utf-8" : "rfc822", ";", STR(clean_addr), (char *) 0); 225 cleanup_out_recipient(state, state->dsn_orcpt, state->dsn_notify, 226 state->orig_rcpt, STR(clean_addr)); 227 if (state->recip) /* This can happen */ 228 myfree(state->recip); 229 state->recip = mystrdup(STR(clean_addr)); /* Used by Milter client */ 230 if ((state->flags & CLEANUP_FLAG_BCC_OK) 231 && *STR(clean_addr) 232 && cleanup_rcpt_bcc_maps) { 233 if ((bcc = mail_addr_find(cleanup_rcpt_bcc_maps, STR(clean_addr), 234 IGNORE_EXTENSION)) != 0) { 235 cleanup_addr_bcc(state, bcc); 236 } else if (cleanup_rcpt_bcc_maps->error) { 237 msg_warn("%s: %s map lookup problem -- " 238 "message not accepted, try again later", 239 state->queue_id, cleanup_rcpt_bcc_maps->title); 240 state->errs |= CLEANUP_STAT_WRITE; 241 } 242 } 243 vstring_free(clean_addr); 244 } 245 246 /* cleanup_addr_bcc_dsn - process automatic BCC recipient */ 247 248 void cleanup_addr_bcc_dsn(CLEANUP_STATE *state, const char *bcc, 249 const char *dsn_orcpt, int dsn_notify) 250 { 251 VSTRING *clean_addr = vstring_alloc(100); 252 253 /* 254 * Note: BCC addresses are supplied locally, and must be rewritten in the 255 * local address rewriting context. 256 */ 257 cleanup_rewrite_internal(MAIL_ATTR_RWR_LOCAL, clean_addr, bcc); 258 if (state->flags & CLEANUP_FLAG_MAP_OK) { 259 if (cleanup_rcpt_canon_maps 260 && (cleanup_rcpt_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT)) 261 cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps, 262 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 263 if (cleanup_comm_canon_maps 264 && (cleanup_comm_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT)) 265 cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps, 266 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 267 if (cleanup_masq_domains 268 && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT)) 269 cleanup_masquerade_internal(state, clean_addr, cleanup_masq_domains); 270 } 271 /* Fix 20140711: Auto-detect an UTF8 recipient. */ 272 if (var_smtputf8_enable && *STR(clean_addr) && !allascii(STR(clean_addr)) 273 && valid_utf8_string(STR(clean_addr), LEN(clean_addr))) { 274 /* Fix 20140713: request SMTPUTF8 support selectively. */ 275 if (state->flags & CLEANUP_FLAG_AUTOUTF8) 276 state->smtputf8 |= SMTPUTF8_FLAG_REQUESTED; 277 } 278 cleanup_out_recipient(state, dsn_orcpt, dsn_notify, 279 STR(clean_addr), STR(clean_addr)); 280 vstring_free(clean_addr); 281 } 282