Current File : //root/postfix-3.2.0/src/local/bounce_workaround.c |
/*++
/* NAME
/* bounce_workaround 3
/* SUMMARY
/* Send non-delivery notification with sender override
/* SYNOPSIS
/* #include "local.h"
/*
/* int bounce_workaround(state)
/* LOCAL_STATE state;
/* DESCRIPTION
/* This module works around a limitation in the bounce daemon
/* protocol, namely, the assumption that the envelope sender
/* address in a queue file is the delivery status notification
/* address for all recipients in that queue file. The assumption
/* is not valid when the local(8) delivery agent overrides the
/* envelope sender address by an owner- alias, for one or more
/* recipients in the queue file.
/*
/* Sender address override is a problem only when delivering
/* to command or file, or when breaking a Delivered-To loop.
/* The local(8) delivery agent saves normal recipients to a
/* new queue file, together with the replacement envelope
/* sender address; delivery then proceeds from that new queue
/* file, and no workaround is needed.
/*
/* The workaround sends one non-delivery notification for each
/* failed delivery that has a replacement sender address. The
/* notifications are not aggregated, unlike notifications to
/* non-replaced sender addresses. In practice, a local alias
/* rarely has more than one file or command destination (if
/* only because soft error handling is problematic).
/*
/* Arguments:
/* .IP state
/* The attributes that specify the message, recipient and more.
/* Attributes describing alias, include or forward expansion.
/* A table with the results from expanding aliases or lists.
/* A table with delivered-to: addresses taken from the message.
/* The non-delivery status must be either 4.X.X or 5.X.X.
/* DIAGNOSTICS
/* Fatal errors: out of memory. The result is non-zero when
/* the operation should be tried again. Warnings: malformed
/* address.
/* BUGS
/* The proper fix is to record in the bounce logfile an error
/* return address for each individual recipient. This would
/* eliminate the need for VERP-specific bounce protocol code,
/* and would move complexity from the bounce client side to
/* the bounce server side where it more likely belongs.
/* 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 <strings.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <vstring.h>
#include <split_at.h>
/* Global library. */
#include <mail_params.h>
#include <strip_addr.h>
#include <stringops.h>
#include <bounce.h>
#include <defer.h>
#include <split_addr.h>
#include <canon_addr.h>
/* Application-specific. */
#include "local.h"
int bounce_workaround(LOCAL_STATE state)
{
const char *myname = "bounce_workaround";
VSTRING *canon_owner = 0;
int rcpt_stat;
/*
* Look up the substitute sender address.
*/
if (var_ownreq_special) {
char *stripped_recipient;
char *owner_alias;
const char *owner_expansion;
#define FIND_OWNER(lhs, rhs, addr) { \
lhs = concatenate("owner-", addr, (char *) 0); \
(void) split_at_right(lhs, '@'); \
rhs = maps_find(alias_maps, lhs, DICT_FLAG_NONE); \
}
FIND_OWNER(owner_alias, owner_expansion, state.msg_attr.rcpt.address);
if (alias_maps->error == 0 && owner_expansion == 0
&& (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
(char **) 0,
var_rcpt_delim)) != 0) {
myfree(owner_alias);
FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
myfree(stripped_recipient);
}
if (alias_maps->error == 0 && owner_expansion != 0) {
canon_owner = canon_addr_internal(vstring_alloc(10),
var_exp_own_alias ?
owner_expansion : owner_alias);
SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
}
myfree(owner_alias);
if (alias_maps->error != 0) {
/* At this point, canon_owner == 0. */
dsb_simple(state.msg_attr.why, "4.3.0",
"alias database unavailable");
return (defer_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr)));
}
}
/*
* Send a delivery status notification with a single recipient to the
* substitute sender address, before completion of the delivery request.
*/
if (canon_owner) {
rcpt_stat =
(STR(state.msg_attr.why->status)[0] == '4' ?
defer_one : bounce_one)
(BOUNCE_FLAGS(state.request),
BOUNCE_ONE_ATTR(state.msg_attr));
vstring_free(canon_owner);
}
/*
* Send a regular delivery status notification, after completion of the
* delivery request.
*/
else {
rcpt_stat =
(STR(state.msg_attr.why->status)[0] == '4' ?
defer_append : bounce_append)
(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr));
}
return (rcpt_stat);
}