1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
|
/*++
/* NAME
/* smtp_trouble 3
/* SUMMARY
/* error handler policies
/* SYNOPSIS
/* #include "smtp.h"
/*
/* int smtp_site_fail(state, code, format, ...)
/* SMTP_STATE *state;
/* int code;
/* char *format;
/*
/* int smtp_mesg_fail(state, code, format, ...)
/* SMTP_STATE *state;
/* int code;
/* char *format;
/*
/* void smtp_rcpt_fail(state, code, recipient, format, ...)
/* SMTP_STATE *state;
/* int code;
/* RECIPIENT *recipient;
/* char *format;
/*
/* int smtp_stream_except(state, exception, description)
/* SMTP_STATE *state;
/* int exception;
/* char *description;
/* DESCRIPTION
/* This module handles all non-fatal errors that can happen while
/* attempting to deliver mail via SMTP, and implements the policy
/* of how to deal with the error. Depending on the nature of
/* the problem, delivery of a single message is deferred, delivery
/* of all messages to the same domain is deferred, or one or more
/* recipients are given up as non-deliverable and a bounce log is
/* updated.
/*
/* In addition, when an unexpected response code is seen such
/* as 3xx where only 4xx or 5xx are expected, or any error code
/* that suggests a syntax error or something similar, the
/* protocol error flag is set so that the postmaster receives
/* a transcript of the session. No notification is generated for
/* what appear to be configuration errors - very likely, they
/* would suffer the same problem and just cause more trouble.
/*
/* smtp_site_fail() handles the case where the program fails to
/* complete the initial SMTP handshake: the server is not reachable,
/* is not running, does not want talk to us, or we talk to ourselves.
/* The \fIcode\fR gives an error status code; the \fIformat\fR
/* argument gives a textual description. The policy is: soft
/* error: defer delivery of all messages to this domain; hard
/* error: bounce all recipients of this message.
/* The result is non-zero.
/*
/* smtp_mesg_fail() handles the case where the smtp server
/* does not accept the sender address or the message data.
/* The policy is: soft errors: defer delivery of this message;
/* hard error: bounce all recipients of this message.
/* The result is non-zero.
/*
/* smtp_rcpt_fail() handles the case where a recipient is not
/* accepted by the server for reasons other than that the server
/* recipient limit is reached. The policy is: soft error: defer
/* delivery to this recipient; hard error: bounce this recipient.
/*
/* smtp_stream_except() handles the exceptions generated by
/* the smtp_stream(3) module (i.e. timeouts and I/O errors).
/* The \fIexception\fR argument specifies the type of problem.
/* The \fIdescription\fR argument describes at what stage of
/* the SMTP dialog the problem happened. The policy is to defer
/* delivery of all messages to the same domain. The result is non-zero.
/* DIAGNOSTICS
/* Panic: unknown exception code.
/* SEE ALSO
/* smtp_proto(3) smtp high-level protocol
/* smtp_stream(3) smtp low-level protocol
/* defer(3) basic message defer interface
/* bounce(3) basic message bounce interface
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
#include <setjmp.h>
#include <stdarg.h>
/* Utility library. */
#include <msg.h>
#include <vstring.h>
#include <stringops.h>
#include <mymalloc.h>
/* Global library. */
#include <smtp_stream.h>
#include <deliver_request.h>
#include <deliver_completed.h>
#include <bounce.h>
#include <defer.h>
#include <mail_error.h>
/* Application-specific. */
#include "smtp.h"
#define SMTP_SOFT(code) (((code) / 100) == 4)
#define SMTP_HARD(code) (((code) / 100) == 5)
#define KEEP BOUNCE_FLAG_KEEP
/* smtp_check_code - check response code */
static void smtp_check_code(SMTP_STATE *state, int code)
{
/*
* The intention of this stuff is to alert the postmaster when the local
* Postfix SMTP client screws up, protocol wise. RFC 821 says that x0z
* replies "refer to syntax errors, syntactically correct commands that
* don't fit any functional category, and unimplemented or superfluous
* commands". Unfortunately, this also triggers postmaster notices when
* remote servers screw up, protocol wise. This is becoming a common
* problem now that response codes are configured manually as part of
* anti-UCE systems, by people who aren't aware of RFC details.
*/
if ((!SMTP_SOFT(code) && !SMTP_HARD(code))
|| code == 555 /* RFC 1869, section 6.1. */
|| (code >= 500 && code < 510))
state->error_mask |= MAIL_ERROR_PROTOCOL;
}
/* smtp_site_fail - defer site or bounce recipients */
int smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
{
DELIVER_REQUEST *request = state->request;
SMTP_SESSION *session = state->session;
RECIPIENT *rcpt;
int status;
int nrcpt;
int soft_error = SMTP_SOFT(code);
va_list ap;
VSTRING *why = vstring_alloc(100);
/*
* Initialize.
*/
va_start(ap, format);
vstring_vsprintf(why, format, ap);
va_end(ap);
/*
* If this is a soft error, postpone further deliveries to this domain.
* Otherwise, generate a bounce record for each recipient.
*/
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset == 0)
continue;
status = (soft_error ? defer_append : bounce_append)
(KEEP, request->queue_id, rcpt->address,
session ? session->namaddr : "none",
request->arrival_time, "%s", vstring_str(why));
if (status == 0) {
deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0;
}
state->status |= status;
}
if (soft_error && request->hop_status == 0)
request->hop_status = mystrdup(vstring_str(why));
/*
* Cleanup.
*/
vstring_free(why);
return (-1);
}
/* smtp_mesg_fail - defer message or bounce all recipients */
int smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
{
DELIVER_REQUEST *request = state->request;
SMTP_SESSION *session = state->session;
RECIPIENT *rcpt;
int status;
int nrcpt;
va_list ap;
VSTRING *why = vstring_alloc(100);
/*
* Initialize.
*/
va_start(ap, format);
vstring_vsprintf(why, format, ap);
va_end(ap);
/*
* If this is a soft error, postpone delivery of this message. Otherwise,
* generate a bounce record for each recipient.
*/
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset == 0)
continue;
status = (SMTP_SOFT(code) ? defer_append : bounce_append)
(KEEP, request->queue_id, rcpt->address,
session->namaddr, request->arrival_time,
"%s", vstring_str(why));
if (status == 0) {
deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0;
}
state->status |= status;
}
smtp_check_code(state, code);
/*
* Cleanup.
*/
vstring_free(why);
return (-1);
}
/* smtp_rcpt_fail - defer or bounce recipient */
void smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
char *format,...)
{
DELIVER_REQUEST *request = state->request;
SMTP_SESSION *session = state->session;
int status;
va_list ap;
/*
* If this is a soft error, postpone delivery to this recipient.
* Otherwise, generate a bounce record for this recipient.
*/
va_start(ap, format);
status = (SMTP_SOFT(code) ? vdefer_append : vbounce_append)
(KEEP, request->queue_id, rcpt->address, session->namaddr,
request->arrival_time, format, ap);
va_end(ap);
if (status == 0) {
deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0;
}
smtp_check_code(state, code);
state->status |= status;
}
/* smtp_stream_except - defer domain after I/O problem */
int smtp_stream_except(SMTP_STATE *state, int code, char *description)
{
DELIVER_REQUEST *request = state->request;
SMTP_SESSION *session = state->session;
RECIPIENT *rcpt;
int nrcpt;
VSTRING *why = vstring_alloc(100);
/*
* Initialize.
*/
switch (code) {
default:
msg_panic("smtp_stream_except: unknown exception %d", code);
case SMTP_ERR_EOF:
vstring_sprintf(why, "lost connection with %s while %s",
session->namaddr, description);
break;
case SMTP_ERR_TIME:
vstring_sprintf(why, "conversation with %s timed out while %s",
session->namaddr, description);
break;
}
/*
* At this point, the status of individual recipients remains unresolved.
* All we know is that we should stay away from this host for a while.
*/
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset == 0)
continue;
state->status |= defer_append(KEEP, request->queue_id,
rcpt->address, session->namaddr,
request->arrival_time,
"%s", vstring_str(why));
}
/*
* Cleanup.
*/
vstring_free(why);
return (-1);
}
|