1/* $NetBSD: bounce_trace_service.c,v 1.2 2017/02/14 01:16:44 christos Exp $ */ 2 3/*++ 4/* NAME 5/* bounce_trace_service 3 6/* SUMMARY 7/* send status report to sender, server side 8/* SYNOPSIS 9/* #include "bounce_service.h" 10/* 11/* int bounce_trace_service(flags, service, queue_name, queue_id, 12/* encoding, smtputf8, sender, envid, 13/* ret, templates) 14/* int flags; 15/* char *service; 16/* char *queue_name; 17/* char *queue_id; 18/* char *encoding; 19/* int smtputf8; 20/* char *sender; 21/* char *envid; 22/* int ret; 23/* BOUNCE_TEMPLATES *templates; 24/* DESCRIPTION 25/* This module implements the server side of the trace_flush() 26/* (send delivery notice) request. The logfile 27/* is removed after the notice is posted. 28/* 29/* A status report includes a prelude with human-readable text, 30/* a DSN-style report, and the email message that was subject of 31/* the status report. 32/* 33/* When a status report is sent, the sender address is the empty 34/* address. 35/* DIAGNOSTICS 36/* Fatal error: error opening existing file. 37/* BUGS 38/* SEE ALSO 39/* bounce(3) basic bounce service client interface 40/* LICENSE 41/* .ad 42/* .fi 43/* The Secure Mailer license must be distributed with this software. 44/* AUTHOR(S) 45/* Wietse Venema 46/* IBM T.J. Watson Research 47/* P.O. Box 704 48/* Yorktown Heights, NY 10598, USA 49/*--*/ 50 51/* System library. */ 52 53#include <sys_defs.h> 54#include <fcntl.h> 55#include <errno.h> 56#include <string.h> 57#include <ctype.h> 58 59/* Utility library. */ 60 61#include <msg.h> 62#include <vstream.h> 63#include <stringops.h> 64 65/* Global library. */ 66 67#include <mail_params.h> 68#include <mail_queue.h> 69#include <post_mail.h> 70#include <mail_addr.h> 71#include <mail_error.h> 72#include <dsn_mask.h> 73#include <rec_type.h> 74#include <deliver_request.h> /* USR_VRFY and RECORD flags */ 75 76/* Application-specific. */ 77 78#include "bounce_service.h" 79 80#define STR vstring_str 81 82/* bounce_trace_service - send a delivery status notice */ 83 84int bounce_trace_service(int flags, char *service, char *queue_name, 85 char *queue_id, char *encoding, 86 int smtputf8, 87 char *recipient, char *dsn_envid, 88 int unused_dsn_ret, 89 BOUNCE_TEMPLATES *ts) 90{ 91 BOUNCE_INFO *bounce_info; 92 int bounce_status = 1; 93 VSTREAM *bounce; 94 int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, 95 var_notify_classes); 96 VSTRING *new_id; 97 int count; 98 const char *sender; 99 100 /* 101 * For consistency with fail/delay notifications, send notification for a 102 * non-bounce message as a single-bounce message, send notification for a 103 * single-bounce message as a double-bounce message, and drop requests to 104 * send notification for a double-bounce message. 105 */ 106#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */ 107 108 if (strcasecmp_utf8(recipient, mail_addr_double_bounce()) == 0) { 109 msg_info("%s: not sending trace/success notification for " 110 "double-bounce message", queue_id); 111 return (0); 112 } else if (*recipient == 0) { 113 if ((notify_mask & MAIL_ERROR_2BOUNCE) != 0) { 114 recipient = var_2bounce_rcpt; 115 sender = mail_addr_double_bounce(); 116 } else { 117 msg_info("%s: not sending trace/success notification " 118 "for single-bounce message", queue_id); 119 if (mail_queue_remove(service, queue_id) && errno != ENOENT) 120 msg_fatal("remove %s %s: %m", service, queue_id); 121 return (0); 122 } 123 } else { 124 /* Always send notification for non-bounce message. */ 125 sender = NULL_SENDER; 126 } 127 128 /* 129 * Initialize. Open queue file, bounce log, etc. 130 * 131 * XXX DSN The trace service produces information from the trace logfile 132 * which is used for three types of reports: 133 * 134 * a) "what-if" reports that show what would happen without actually 135 * delivering mail (sendmail -bv). 136 * 137 * b) A report of actual deliveries (sendmail -v). 138 * 139 * c) DSN NOTIFY=SUCCESS reports of successful delivery ("delivered", 140 * "expanded" or "relayed"). 141 */ 142#define NON_DSN_FLAGS (DEL_REQ_FLAG_USR_VRFY | DEL_REQ_FLAG_RECORD) 143 144 bounce_info = bounce_mail_init(service, queue_name, queue_id, 145 encoding, smtputf8, dsn_envid, 146 flags & NON_DSN_FLAGS ? 147 ts->verify : ts->success); 148 149 /* 150 * XXX With multi-recipient mail some queue file recipients may have 151 * NOTIFY=SUCCESS and others not. Depending on what subset of recipients 152 * are delivered, a trace file may or may not be created. Even when the 153 * last partial delivery attempt had no NOTIFY=SUCCESS recipients, a 154 * trace file may still exist from a previous partial delivery attempt. 155 * So as long as any recipient in the original queue file had 156 * NOTIFY=SUCCESS we have to always look for the trace file and be 157 * prepared for the file not to exist. 158 * 159 * See also comments in qmgr/qmgr_active.c. 160 */ 161 if (bounce_info->log_handle == 0) { 162 if (msg_verbose) 163 msg_info("%s: no trace file -- not sending a notification", 164 queue_id); 165 bounce_mail_free(bounce_info); 166 return (0); 167 } 168#define NULL_TRACE_FLAGS 0 169 170 /* 171 * Send a single bounce with a template message header, some boilerplate 172 * text that pretends that we are a polite mail system, the text with 173 * per-recipient status, and a copy of the original message. 174 * 175 * XXX DSN We use the same trace file for "what-if", "verbose delivery" and 176 * "success" delivery reports. This saves file system overhead because 177 * there are fewer potential left-over files to remove up when we create 178 * a new queue file. 179 */ 180 new_id = vstring_alloc(10); 181 if ((bounce = post_mail_fopen_nowait(sender, recipient, 182 MAIL_SRC_MASK_BOUNCE, 183 NULL_TRACE_FLAGS, 184 smtputf8, 185 new_id)) != 0) { 186 count = -1; 187 if (bounce_header(bounce, bounce_info, recipient, 188 NO_POSTMASTER_COPY) == 0 189 && bounce_boilerplate(bounce, bounce_info) == 0 190 && (count = bounce_diagnostic_log(bounce, bounce_info, 191 DSN_NOTIFY_OVERRIDE)) > 0 192 && bounce_header_dsn(bounce, bounce_info) == 0 193 && bounce_diagnostic_dsn(bounce, bounce_info, 194 DSN_NOTIFY_OVERRIDE) > 0) { 195 bounce_original(bounce, bounce_info, DSN_RET_HDRS); 196 bounce_status = post_mail_fclose(bounce); 197 if (bounce_status == 0) 198 msg_info("%s: sender delivery status notification: %s", 199 queue_id, STR(new_id)); 200 } else { 201 (void) vstream_fclose(bounce); 202 if (count == 0) 203 bounce_status = 0; 204 } 205 } 206 207 /* 208 * Examine the completion status. Delete the trace log file only when the 209 * status notice was posted successfully. 210 */ 211 if (bounce_status == 0 && mail_queue_remove(service, queue_id) 212 && errno != ENOENT) 213 msg_fatal("remove %s %s: %m", service, queue_id); 214 215 /* 216 * Cleanup. 217 */ 218 bounce_mail_free(bounce_info); 219 vstring_free(new_id); 220 221 return (bounce_status); 222} 223