1 /* $NetBSD: cleanup_addr.c,v 1.3 2020/03/18 19:05:15 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 /* Wietse Venema 70 /* Google, Inc. 71 /* 111 8th Avenue 72 /* New York, NY 10011, USA 73 /*--*/ 74 75 /* System library. */ 76 77 #include <sys_defs.h> 78 #include <string.h> 79 #include <stdlib.h> 80 81 /* Utility library. */ 82 83 #include <msg.h> 84 #include <vstring.h> 85 #include <vstream.h> 86 #include <mymalloc.h> 87 #include <stringops.h> 88 89 /* Global library. */ 90 91 #include <rec_type.h> 92 #include <record.h> 93 #include <cleanup_user.h> 94 #include <mail_params.h> 95 #include <ext_prop.h> 96 #include <mail_addr.h> 97 #include <canon_addr.h> 98 #include <mail_addr_find.h> 99 #include <mail_proto.h> 100 #include <dsn_mask.h> 101 #include <smtputf8.h> 102 103 /* Application-specific. */ 104 105 #include "cleanup.h" 106 107 #define STR vstring_str 108 #define LEN VSTRING_LEN 109 #define IGNORE_EXTENSION (char **) 0 110 111 /* cleanup_addr_sender - process envelope sender record */ 112 113 off_t cleanup_addr_sender(CLEANUP_STATE *state, const char *buf) 114 { 115 const char myname[] = "cleanup_addr_sender"; 116 VSTRING *clean_addr = vstring_alloc(100); 117 off_t after_sender_offs = 0; 118 const char *bcc; 119 size_t len; 120 121 /* 122 * Note: an unqualified envelope address is for all practical purposes 123 * equivalent to a fully qualified local address, both for delivery and 124 * for replying. Having to support both forms is error prone, therefore 125 * an incomplete envelope address is rewritten to fully qualified form in 126 * the local domain context. 127 * 128 * 20000520: Replace mailer-daemon@$myorigin by the null address, to handle 129 * bounced mail traffic more robustly. 130 */ 131 cleanup_rewrite_internal(MAIL_ATTR_RWR_LOCAL, clean_addr, buf); 132 if (strncasecmp_utf8(STR(clean_addr), MAIL_ADDR_MAIL_DAEMON "@", 133 sizeof(MAIL_ADDR_MAIL_DAEMON)) == 0) { 134 canon_addr_internal(state->temp1, MAIL_ADDR_MAIL_DAEMON); 135 if (strcasecmp_utf8(STR(clean_addr), STR(state->temp1)) == 0) 136 vstring_strcpy(clean_addr, ""); 137 } 138 if (state->flags & CLEANUP_FLAG_MAP_OK) { 139 if (cleanup_send_canon_maps 140 && (cleanup_send_canon_flags & CLEANUP_CANON_FLAG_ENV_FROM)) 141 cleanup_map11_internal(state, clean_addr, cleanup_send_canon_maps, 142 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 143 if (cleanup_comm_canon_maps 144 && (cleanup_comm_canon_flags & CLEANUP_CANON_FLAG_ENV_FROM)) 145 cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps, 146 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 147 if (cleanup_masq_domains 148 && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_FROM)) 149 cleanup_masquerade_internal(state, clean_addr, cleanup_masq_domains); 150 } 151 /* Fix 20140711: Auto-detect an UTF8 sender. */ 152 if (var_smtputf8_enable && *STR(clean_addr) && !allascii(STR(clean_addr)) 153 && valid_utf8_string(STR(clean_addr), LEN(clean_addr))) { 154 state->smtputf8 |= SMTPUTF8_FLAG_SENDER; 155 /* Fix 20140713: request SMTPUTF8 support selectively. */ 156 if (state->flags & CLEANUP_FLAG_AUTOUTF8) 157 state->smtputf8 |= SMTPUTF8_FLAG_REQUESTED; 158 } 159 CLEANUP_OUT_BUF(state, REC_TYPE_FROM, clean_addr); 160 if (state->sender) /* XXX Can't happen */ 161 myfree(state->sender); 162 state->sender = mystrdup(STR(clean_addr)); /* Used by Milter client */ 163 /* Fix 20160310: Moved from cleanup_envelope.c. */ 164 if (state->milters || cleanup_milters) { 165 /* Make room to replace sender. */ 166 if ((len = LEN(clean_addr)) < REC_TYPE_PTR_PAYL_SIZE) 167 rec_pad(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_PAYL_SIZE - len); 168 /* Remember the after-sender record offset. */ 169 if ((after_sender_offs = vstream_ftell(state->dst)) < 0) 170 msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path); 171 } 172 if ((state->flags & CLEANUP_FLAG_BCC_OK) 173 && *STR(clean_addr) 174 && cleanup_send_bcc_maps) { 175 if ((bcc = mail_addr_find_to_internal(cleanup_send_bcc_maps, 176 STR(clean_addr), 177 IGNORE_EXTENSION)) != 0) { 178 cleanup_addr_bcc(state, bcc); 179 } else if (cleanup_send_bcc_maps->error) { 180 msg_warn("%s: %s map lookup problem -- " 181 "message not accepted, try again later", 182 state->queue_id, cleanup_send_bcc_maps->title); 183 state->errs |= CLEANUP_STAT_WRITE; 184 } 185 } 186 vstring_free(clean_addr); 187 return after_sender_offs; 188 } 189 190 /* cleanup_addr_recipient - process envelope recipient */ 191 192 void cleanup_addr_recipient(CLEANUP_STATE *state, const char *buf) 193 { 194 VSTRING *clean_addr = vstring_alloc(100); 195 const char *bcc; 196 197 /* 198 * Note: an unqualified envelope address is for all practical purposes 199 * equivalent to a fully qualified local address, both for delivery and 200 * for replying. Having to support both forms is error prone, therefore 201 * an incomplete envelope address is rewritten to fully qualified form in 202 * the local domain context. 203 */ 204 cleanup_rewrite_internal(MAIL_ATTR_RWR_LOCAL, 205 clean_addr, *buf ? buf : var_empty_addr); 206 if (state->flags & CLEANUP_FLAG_MAP_OK) { 207 if (cleanup_rcpt_canon_maps 208 && (cleanup_rcpt_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT)) 209 cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps, 210 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 211 if (cleanup_comm_canon_maps 212 && (cleanup_comm_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT)) 213 cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps, 214 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 215 if (cleanup_masq_domains 216 && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT)) 217 cleanup_masquerade_internal(state, clean_addr, cleanup_masq_domains); 218 } 219 /* Fix 20140711: Auto-detect an UTF8 recipient. */ 220 if (var_smtputf8_enable && *STR(clean_addr) && !allascii(STR(clean_addr)) 221 && valid_utf8_string(STR(clean_addr), LEN(clean_addr))) { 222 /* Fix 20140713: request SMTPUTF8 support selectively. */ 223 if (state->flags & CLEANUP_FLAG_AUTOUTF8) 224 state->smtputf8 |= SMTPUTF8_FLAG_REQUESTED; 225 } 226 /* Fix 20141024: Don't fake up a "bare" DSN original rcpt in smtp(8). */ 227 if (state->dsn_orcpt == 0 && *STR(clean_addr) != 0) 228 state->dsn_orcpt = concatenate((!allascii(STR(clean_addr)) 229 && (state->smtputf8 & SMTPUTF8_FLAG_REQUESTED)) ? 230 "utf-8" : "rfc822", ";", STR(clean_addr), (char *) 0); 231 cleanup_out_recipient(state, state->dsn_orcpt, state->dsn_notify, 232 state->orig_rcpt, STR(clean_addr)); 233 if (state->recip) /* This can happen */ 234 myfree(state->recip); 235 state->recip = mystrdup(STR(clean_addr)); /* Used by Milter client */ 236 if ((state->flags & CLEANUP_FLAG_BCC_OK) 237 && *STR(clean_addr) 238 && cleanup_rcpt_bcc_maps) { 239 if ((bcc = mail_addr_find_to_internal(cleanup_rcpt_bcc_maps, 240 STR(clean_addr), 241 IGNORE_EXTENSION)) != 0) { 242 cleanup_addr_bcc(state, bcc); 243 } else if (cleanup_rcpt_bcc_maps->error) { 244 msg_warn("%s: %s map lookup problem -- " 245 "message not accepted, try again later", 246 state->queue_id, cleanup_rcpt_bcc_maps->title); 247 state->errs |= CLEANUP_STAT_WRITE; 248 } 249 } 250 vstring_free(clean_addr); 251 } 252 253 /* cleanup_addr_bcc_dsn - process automatic BCC recipient */ 254 255 void cleanup_addr_bcc_dsn(CLEANUP_STATE *state, const char *bcc, 256 const char *dsn_orcpt, int dsn_notify) 257 { 258 VSTRING *clean_addr = vstring_alloc(100); 259 260 /* 261 * Note: BCC addresses are supplied locally, and must be rewritten in the 262 * local address rewriting context. 263 */ 264 cleanup_rewrite_internal(MAIL_ATTR_RWR_LOCAL, clean_addr, bcc); 265 if (state->flags & CLEANUP_FLAG_MAP_OK) { 266 if (cleanup_rcpt_canon_maps 267 && (cleanup_rcpt_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT)) 268 cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps, 269 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 270 if (cleanup_comm_canon_maps 271 && (cleanup_comm_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT)) 272 cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps, 273 cleanup_ext_prop_mask & EXT_PROP_CANONICAL); 274 if (cleanup_masq_domains 275 && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT)) 276 cleanup_masquerade_internal(state, clean_addr, cleanup_masq_domains); 277 } 278 /* Fix 20140711: Auto-detect an UTF8 recipient. */ 279 if (var_smtputf8_enable && *STR(clean_addr) && !allascii(STR(clean_addr)) 280 && valid_utf8_string(STR(clean_addr), LEN(clean_addr))) { 281 /* Fix 20140713: request SMTPUTF8 support selectively. */ 282 if (state->flags & CLEANUP_FLAG_AUTOUTF8) 283 state->smtputf8 |= SMTPUTF8_FLAG_REQUESTED; 284 } 285 cleanup_out_recipient(state, dsn_orcpt, dsn_notify, 286 STR(clean_addr), STR(clean_addr)); 287 vstring_free(clean_addr); 288 } 289