Postfix3.3.1
bounce_workaround.c
[詳解]
1 /*++
2 /* NAME
3 /* bounce_workaround 3
4 /* SUMMARY
5 /* Send non-delivery notification with sender override
6 /* SYNOPSIS
7 /* #include "local.h"
8 /*
9 /* int bounce_workaround(state)
10 /* LOCAL_STATE state;
11 /* DESCRIPTION
12 /* This module works around a limitation in the bounce daemon
13 /* protocol, namely, the assumption that the envelope sender
14 /* address in a queue file is the delivery status notification
15 /* address for all recipients in that queue file. The assumption
16 /* is not valid when the local(8) delivery agent overrides the
17 /* envelope sender address by an owner- alias, for one or more
18 /* recipients in the queue file.
19 /*
20 /* Sender address override is a problem only when delivering
21 /* to command or file, or when breaking a Delivered-To loop.
22 /* The local(8) delivery agent saves normal recipients to a
23 /* new queue file, together with the replacement envelope
24 /* sender address; delivery then proceeds from that new queue
25 /* file, and no workaround is needed.
26 /*
27 /* The workaround sends one non-delivery notification for each
28 /* failed delivery that has a replacement sender address. The
29 /* notifications are not aggregated, unlike notifications to
30 /* non-replaced sender addresses. In practice, a local alias
31 /* rarely has more than one file or command destination (if
32 /* only because soft error handling is problematic).
33 /*
34 /* Arguments:
35 /* .IP state
36 /* The attributes that specify the message, recipient and more.
37 /* Attributes describing alias, include or forward expansion.
38 /* A table with the results from expanding aliases or lists.
39 /* A table with delivered-to: addresses taken from the message.
40 /* The non-delivery status must be either 4.X.X or 5.X.X.
41 /* DIAGNOSTICS
42 /* Fatal errors: out of memory. The result is non-zero when
43 /* the operation should be tried again. Warnings: malformed
44 /* address.
45 /* BUGS
46 /* The proper fix is to record in the bounce logfile an error
47 /* return address for each individual recipient. This would
48 /* eliminate the need for VERP-specific bounce protocol code,
49 /* and would move complexity from the bounce client side to
50 /* the bounce server side where it more likely belongs.
51 /* LICENSE
52 /* .ad
53 /* .fi
54 /* The Secure Mailer license must be distributed with this
55 /* software.
56 /* AUTHOR(S)
57 /* Wietse Venema
58 /* IBM T.J. Watson Research
59 /* P.O. Box 704
60 /* Yorktown Heights, NY 10598, USA
61 /*--*/
62 
63 /* System library. */
64 
65 #include <sys_defs.h>
66 #include <strings.h>
67 
68 /* Utility library. */
69 
70 #include <msg.h>
71 #include <mymalloc.h>
72 #include <vstring.h>
73 #include <split_at.h>
74 
75 /* Global library. */
76 
77 #include <mail_params.h>
78 #include <strip_addr.h>
79 #include <stringops.h>
80 #include <bounce.h>
81 #include <defer.h>
82 #include <split_addr.h>
83 #include <canon_addr.h>
84 
85 /* Application-specific. */
86 
87 #include "local.h"
88 
90 {
91  const char *myname = "bounce_workaround";
92  VSTRING *canon_owner = 0;
93  int rcpt_stat;
94 
95  /*
96  * Look up the substitute sender address.
97  */
98  if (var_ownreq_special) {
99  char *stripped_recipient;
100  char *owner_alias;
101  const char *owner_expansion;
102 
103 #define FIND_OWNER(lhs, rhs, addr) { \
104  lhs = concatenate("owner-", addr, (char *) 0); \
105  (void) split_at_right(lhs, '@'); \
106  rhs = maps_find(alias_maps, lhs, DICT_FLAG_NONE); \
107  }
108 
109  FIND_OWNER(owner_alias, owner_expansion, state.msg_attr.rcpt.address);
110  if (alias_maps->error == 0 && owner_expansion == 0
111  && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
112  (char **) 0,
113  var_rcpt_delim)) != 0) {
114  myfree(owner_alias);
115  FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
116  myfree(stripped_recipient);
117  }
118  if (alias_maps->error == 0 && owner_expansion != 0) {
119  canon_owner = canon_addr_internal(vstring_alloc(10),
121  owner_expansion : owner_alias);
122  SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
123  }
124  myfree(owner_alias);
125  if (alias_maps->error != 0) {
126  /* At this point, canon_owner == 0. */
127  dsb_simple(state.msg_attr.why, "4.3.0",
128  "alias database unavailable");
129  return (defer_append(BOUNCE_FLAGS(state.request),
130  BOUNCE_ATTR(state.msg_attr)));
131  }
132  }
133 
134  /*
135  * Send a delivery status notification with a single recipient to the
136  * substitute sender address, before completion of the delivery request.
137  */
138  if (canon_owner) {
139  rcpt_stat =
140  (STR(state.msg_attr.why->status)[0] == '4' ?
142  (BOUNCE_FLAGS(state.request),
143  BOUNCE_ONE_ATTR(state.msg_attr));
144  vstring_free(canon_owner);
145  }
146 
147  /*
148  * Send a regular delivery status notification, after completion of the
149  * delivery request.
150  */
151  else {
152  rcpt_stat =
153  (STR(state.msg_attr.why->status)[0] == '4' ?
155  (BOUNCE_FLAGS(state.request),
156  BOUNCE_ATTR(state.msg_attr));
157  }
158  return (rcpt_stat);
159 }
int var_ownreq_special
Definition: mail_params.c:283
#define BOUNCE_ATTR(attr)
Definition: local.h:134
void myfree(void *ptr)
Definition: mymalloc.c:207
#define SET_OWNER_ATTR(msg_attr, who, level)
Definition: local.h:122
MAPS * alias_maps
Definition: local.c:687
const char * address
#define BOUNCE_ONE_ATTR(attr)
Definition: local.h:137
VSTRING * canon_addr_internal(VSTRING *result, const char *addr)
Definition: canon_addr.c:64
DELIVER_REQUEST * request
Definition: local.h:113
#define BOUNCE_FLAGS(request)
int bounce_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: bounce.c:222
int bounce_one(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: bounce.c:412
char * var_rcpt_delim
Definition: mail_params.c:274
int defer_one(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: defer.c:346
bool var_exp_own_alias
Definition: local.c:672
DELIVER_ATTR msg_attr
Definition: local.h:110
#define STR(x)
Definition: anvil.c:518
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
DSN_BUF * dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
Definition: dsn_buf.c:275
#define FIND_OWNER(lhs, rhs, addr)
int bounce_workaround(LOCAL_STATE state)
int error
Definition: maps.h:25
DSN_BUF * why
Definition: local.h:92
int level
Definition: local.h:109
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define strip_addr
Definition: strip_addr.h:18
int defer_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: defer.c:187
RECIPIENT rcpt
Definition: local.h:79
VSTRING * status
Definition: dsn_buf.h:30