Postfix3.3.1
forward.c
[詳解]
1 /*++
2 /* NAME
3 /* forward 3
4 /* SUMMARY
5 /* message forwarding
6 /* SYNOPSIS
7 /* #include "local.h"
8 /*
9 /* int forward_init()
10 /*
11 /* int forward_append(attr)
12 /* DELIVER_ATTR attr;
13 /*
14 /* int forward_finish(request, attr, cancel)
15 /* DELIVER_REQUEST *request;
16 /* DELIVER_ATTR attr;
17 /* int cancel;
18 /* DESCRIPTION
19 /* This module implements the client interface for message
20 /* forwarding.
21 /*
22 /* forward_init() initializes internal data structures.
23 /*
24 /* forward_append() appends a recipient to the list of recipients
25 /* that will receive a message with the specified message sender
26 /* and delivered-to addresses.
27 /*
28 /* forward_finish() forwards the actual message contents and
29 /* releases the memory allocated by forward_init() and by
30 /* forward_append(). When the \fIcancel\fR argument is true, no
31 /* messages will be forwarded. The \fIattr\fR argument specifies
32 /* the original message delivery attributes as they were before
33 /* alias or forward expansions.
34 /* DIAGNOSTICS
35 /* A non-zero result means that the requested operation should
36 /* be tried again.
37 /* Warnings: problems connecting to the forwarding service,
38 /* corrupt message file. A corrupt message is saved to the
39 /* "corrupt" queue for further inspection.
40 /* Fatal: out of memory.
41 /* Panic: missing forward_init() or forward_finish() call.
42 /* LICENSE
43 /* .ad
44 /* .fi
45 /* The Secure Mailer license must be distributed with this software.
46 /* AUTHOR(S)
47 /* Wietse Venema
48 /* IBM T.J. Watson Research
49 /* P.O. Box 704
50 /* Yorktown Heights, NY 10598, USA
51 /*
52 /* Wietse Venema
53 /* Google, Inc.
54 /* 111 8th Avenue
55 /* New York, NY 10011, USA
56 /*--*/
57 
58 /* System library. */
59 
60 #include <sys_defs.h>
61 #include <sys/time.h>
62 #include <unistd.h>
63 
64 /* Utility library. */
65 
66 #include <msg.h>
67 #include <mymalloc.h>
68 #include <htable.h>
69 #include <argv.h>
70 #include <vstring.h>
71 #include <vstream.h>
72 #include <vstring_vstream.h>
73 #include <iostuff.h>
74 #include <stringops.h>
75 
76 /* Global library. */
77 
78 #include <mail_proto.h>
79 #include <cleanup_user.h>
80 #include <sent.h>
81 #include <record.h>
82 #include <rec_type.h>
83 #include <mark_corrupt.h>
84 #include <mail_date.h>
85 #include <mail_params.h>
86 #include <dsn_mask.h>
87 #include <smtputf8.h>
88 
89 /* Application-specific. */
90 
91 #include "local.h"
92 
93  /*
94  * Use one cleanup service connection for each (delivered to, sender) pair.
95  */
96 static HTABLE *forward_dt;
97 
98 typedef struct FORWARD_INFO {
99  VSTREAM *cleanup; /* clean up service handle */
100  char *queue_id; /* forwarded message queue id */
101  struct timeval posting_time; /* posting time */
102 } FORWARD_INFO;
103 
104 /* forward_init - prepare for forwarding */
105 
106 int forward_init(void)
107 {
108 
109  /*
110  * Sanity checks.
111  */
112  if (forward_dt != 0)
113  msg_panic("forward_init: missing forward_finish call");
114 
115  forward_dt = htable_create(0);
116  return (0);
117 }
118 
119 /* forward_open - open connection to cleanup service */
120 
121 static FORWARD_INFO *forward_open(DELIVER_REQUEST *request, const char *sender)
122 {
123  VSTRING *buffer = vstring_alloc(100);
124  FORWARD_INFO *info;
125  VSTREAM *cleanup;
126 
127 #define FORWARD_OPEN_RETURN(res) do { \
128  vstring_free(buffer); \
129  return (res); \
130  } while (0)
131 
132  /*
133  * Contact the cleanup service and save the new mail queue id. Request
134  * that the cleanup service bounces bad messages to the sender so that we
135  * can avoid the trouble of bounce management.
136  *
137  * In case you wonder what kind of bounces, examples are "too many hops",
138  * "message too large", perhaps some others. The reason not to bounce
139  * ourselves is that we don't really know who the recipients are.
140  */
142  if (cleanup == 0) {
143  msg_warn("connect to %s/%s: %m",
146  }
148  if (attr_scan(cleanup, ATTR_FLAG_STRICT,
150  ATTR_TYPE_END) != 1) {
151  vstream_fclose(cleanup);
153  }
154  info = (FORWARD_INFO *) mymalloc(sizeof(FORWARD_INFO));
155  info->cleanup = cleanup;
156  info->queue_id = mystrdup(STR(buffer));
157  GETTIMEOFDAY(&info->posting_time);
158 
159 #define FORWARD_CLEANUP_FLAGS \
160  (CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_MASK_INTERNAL \
161  | smtputf8_autodetect(MAIL_SRC_MASK_FORWARD) \
162  | ((request->smtputf8 & SMTPUTF8_FLAG_REQUESTED) ? \
163  CLEANUP_FLAG_SMTPUTF8 : 0))
164 
165  attr_print(cleanup, ATTR_FLAG_NONE,
167  ATTR_TYPE_END);
168 
169  /*
170  * Send initial message envelope information. For bounces, set the
171  * designated sender: mailing list owner, posting user, whatever.
172  */
175  rec_fputs(cleanup, REC_TYPE_FROM, sender);
176 
177  /*
178  * Don't send the original envelope ID or full/headers return mask if it
179  * was reset due to mailing list expansion.
180  */
181  if (request->dsn_ret)
182  rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%d",
183  MAIL_ATTR_DSN_RET, request->dsn_ret);
184  if (request->dsn_envid && *(request->dsn_envid))
185  rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%s",
186  MAIL_ATTR_DSN_ENVID, request->dsn_envid);
187 
188  /*
189  * Zero-length attribute values are place holders for unavailable
190  * attribute values. See qmgr_message.c. They are not meant to be
191  * propagated to queue files.
192  */
193 #define PASS_ATTR(fp, name, value) do { \
194  if ((value) && *(value)) \
195  rec_fprintf((fp), REC_TYPE_ATTR, "%s=%s", (name), (value)); \
196  } while (0)
197 
198  /*
199  * XXX encapsulate these as one object.
200  */
201  PASS_ATTR(cleanup, MAIL_ATTR_LOG_CLIENT_NAME, request->client_name);
202  PASS_ATTR(cleanup, MAIL_ATTR_LOG_CLIENT_ADDR, request->client_addr);
203  PASS_ATTR(cleanup, MAIL_ATTR_LOG_PROTO_NAME, request->client_proto);
204  PASS_ATTR(cleanup, MAIL_ATTR_LOG_HELO_NAME, request->client_helo);
205  PASS_ATTR(cleanup, MAIL_ATTR_SASL_METHOD, request->sasl_method);
206  PASS_ATTR(cleanup, MAIL_ATTR_SASL_USERNAME, request->sasl_username);
207  PASS_ATTR(cleanup, MAIL_ATTR_SASL_SENDER, request->sasl_sender);
208  PASS_ATTR(cleanup, MAIL_ATTR_LOG_IDENT, request->log_ident);
209  PASS_ATTR(cleanup, MAIL_ATTR_RWR_CONTEXT, request->rewrite_context);
210 
211  FORWARD_OPEN_RETURN(info);
212 }
213 
214 /* forward_append - append recipient to message envelope */
215 
217 {
218  FORWARD_INFO *info;
219  HTABLE *table_snd;
220 
221  /*
222  * Sanity checks.
223  */
224  if (msg_verbose)
225  msg_info("forward delivered=%s sender=%s recip=%s",
226  attr.delivered, attr.sender, attr.rcpt.address);
227  if (forward_dt == 0)
228  msg_panic("forward_append: missing forward_init call");
229 
230  /*
231  * In order to find the recipient list, first index a table by
232  * delivered-to header address, then by envelope sender address.
233  */
234  if ((table_snd = (HTABLE *) htable_find(forward_dt, attr.delivered)) == 0) {
235  table_snd = htable_create(0);
236  htable_enter(forward_dt, attr.delivered, (void *) table_snd);
237  }
238  if ((info = (FORWARD_INFO *) htable_find(table_snd, attr.sender)) == 0) {
239  if ((info = forward_open(attr.request, attr.sender)) == 0)
240  return (-1);
241  htable_enter(table_snd, attr.sender, (void *) info);
242  }
243 
244  /*
245  * Append the recipient to the message envelope. Don't send the original
246  * recipient or notification mask if it was reset due to mailing list
247  * expansion.
248  */
249  if (*attr.rcpt.dsn_orcpt)
250  rec_fprintf(info->cleanup, REC_TYPE_ATTR, "%s=%s",
252  if (attr.rcpt.dsn_notify)
253  rec_fprintf(info->cleanup, REC_TYPE_ATTR, "%s=%d",
255  if (*attr.rcpt.orig_addr)
258 
259  return (vstream_ferror(info->cleanup));
260 }
261 
262 /* forward_send - send forwarded message */
263 
264 static int forward_send(FORWARD_INFO *info, DELIVER_REQUEST *request,
265  DELIVER_ATTR attr, char *delivered)
266 {
267  const char *myname = "forward_send";
268  VSTRING *buffer = vstring_alloc(100);
269  VSTRING *folded;
270  int status;
271  int rec_type = 0;
272 
273  /*
274  * Start the message content segment. Prepend our Delivered-To: header to
275  * the message data. Stop at the first error. XXX Rely on the front-end
276  * services to enforce record size limits.
277  */
278  rec_fputs(info->cleanup, REC_TYPE_MESG, "");
279  vstring_strcpy(buffer, delivered);
280  rec_fprintf(info->cleanup, REC_TYPE_NORM, "Received: by %s (%s)",
282  rec_fprintf(info->cleanup, REC_TYPE_NORM, "\tid %s; %s",
283  info->queue_id, mail_date(info->posting_time.tv_sec));
285  folded = vstring_alloc(100);
286  rec_fprintf(info->cleanup, REC_TYPE_NORM, "Delivered-To: %s",
287  casefold(folded, (STR(buffer))));
288  vstring_free(folded);
289  }
290  if ((status = vstream_ferror(info->cleanup)) == 0)
291  if (vstream_fseek(attr.fp, attr.offset, SEEK_SET) < 0)
292  msg_fatal("%s: seek queue file %s: %m:",
293  myname, VSTREAM_PATH(attr.fp));
294  while (status == 0 && (rec_type = rec_get(attr.fp, buffer, 0)) > 0) {
295  if (rec_type != REC_TYPE_CONT && rec_type != REC_TYPE_NORM)
296  break;
297  status = (REC_PUT_BUF(info->cleanup, rec_type, buffer) != rec_type);
298  }
299  if (status == 0 && rec_type != REC_TYPE_XTRA) {
300  msg_warn("%s: bad record type: %d in message content",
301  info->queue_id, rec_type);
302  status |= mark_corrupt(attr.fp);
303  }
304 
305  /*
306  * Send the end-of-data marker only when there were no errors.
307  */
308  if (status == 0) {
309  rec_fputs(info->cleanup, REC_TYPE_XTRA, "");
310  rec_fputs(info->cleanup, REC_TYPE_END, "");
311  }
312 
313  /*
314  * Retrieve the cleanup service completion status only if there are no
315  * problems.
316  */
317  if (status == 0)
318  if (vstream_fflush(info->cleanup)
321  ATTR_TYPE_END) != 1)
322  status = 1;
323 
324  /*
325  * Log successful forwarding.
326  *
327  * XXX DSN alias and .forward expansion already report SUCCESS, so don't do
328  * it again here.
329  */
330  if (status == 0) {
331  attr.rcpt.dsn_notify =
334  dsb_update(attr.why, "2.0.0", "relayed", DSB_SKIP_RMTA, DSB_SKIP_REPLY,
335  "forwarded as %s", info->queue_id);
336  status = sent(BOUNCE_FLAGS(request), SENT_ATTR(attr));
337  }
338 
339  /*
340  * Cleanup.
341  */
342  vstring_free(buffer);
343  return (status);
344 }
345 
346 /* forward_finish - complete message forwarding requests and clean up */
347 
348 int forward_finish(DELIVER_REQUEST *request, DELIVER_ATTR attr, int cancel)
349 {
350  HTABLE_INFO **dt_list;
351  HTABLE_INFO **dt;
352  HTABLE_INFO **sn_list;
353  HTABLE_INFO **sn;
354  HTABLE *table_snd;
355  char *delivered;
356  char *sender;
357  FORWARD_INFO *info;
358  int status = cancel;
359 
360  /*
361  * Sanity checks.
362  */
363  if (forward_dt == 0)
364  msg_panic("forward_finish: missing forward_init call");
365 
366  /*
367  * Walk over all delivered-to header addresses and over each envelope
368  * sender address.
369  */
370  for (dt = dt_list = htable_list(forward_dt); *dt; dt++) {
371  delivered = dt[0]->key;
372  table_snd = (HTABLE *) dt[0]->value;
373  for (sn = sn_list = htable_list(table_snd); *sn; sn++) {
374  sender = sn[0]->key;
375  info = (FORWARD_INFO *) sn[0]->value;
376  if (status == 0)
377  status |= forward_send(info, request, attr, delivered);
378  if (msg_verbose)
379  msg_info("forward_finish: delivered %s sender %s status %d",
380  delivered, sender, status);
381  (void) vstream_fclose(info->cleanup);
382  myfree(info->queue_id);
383  myfree((void *) info);
384  }
385  myfree((void *) sn_list);
386  htable_free(table_snd, (void (*) (void *)) 0);
387  }
388  myfree((void *) dt_list);
389  htable_free(forward_dt, (void (*) (void *)) 0);
390  forward_dt = 0;
391  return (status);
392 }
int msg_verbose
Definition: msg.c:177
#define SENT_ATTR(attr)
Definition: local.h:142
void htable_free(HTABLE *table, void(*free_fn)(void *))
Definition: htable.c:287
const char * orig_addr
char * var_mail_name
Definition: mail_params.c:230
#define ATTR_FLAG_NONE
Definition: attr.h:98
#define MAIL_ATTR_DSN_NOTIFY
Definition: mail_proto.h:275
void myfree(void *ptr)
Definition: mymalloc.c:207
char * mystrdup(const char *str)
Definition: mymalloc.c:225
char * var_cleanup_service
Definition: mail_params.c:302
const char * address
const char * mail_date(time_t when)
Definition: mail_date.c:54
#define DELIVER_HDR_FWD
Definition: local.h:204
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
DSN_BUF * dsb_update(DSN_BUF *dsb, const char *status, const char *action, const char *mtype, const char *mname, const char *dtype, const char *dtext, const char *format,...)
Definition: dsn_buf.c:239
VSTREAM * mail_connect(const char *class, const char *name, int block_mode)
Definition: mail_connect.c:79
#define ATTR_FLAG_MISSING
Definition: attr.h:99
int forward_init(void)
Definition: forward.c:106
struct timeval posting_time
Definition: forward.c:101
#define MAIL_ATTR_RWR_CONTEXT
Definition: mail_proto.h:163
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
VSTREAM * cleanup
Definition: forward.c:99
DELIVER_REQUEST * request
Definition: local.h:91
#define DSB_SKIP_RMTA
Definition: dsn_buf.h:42
#define MAIL_ATTR_SASL_METHOD
Definition: mail_proto.h:156
#define REC_TYPE_FROM
Definition: rec_type.h:43
#define REC_TYPE_END
Definition: rec_type.h:77
#define FORWARD_OPEN_RETURN(res)
#define MAIL_ATTR_LOG_HELO_NAME
Definition: mail_proto.h:210
Definition: htable.h:25
#define DSN_NOTIFY_NEVER
Definition: dsn_mask.h:43
struct FORWARD_INFO FORWARD_INFO
#define MAIL_ATTR_LOG_PROTO_NAME
Definition: mail_proto.h:211
#define BOUNCE_FLAGS(request)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
#define casefold(dst, src)
Definition: stringops.h:67
HTABLE * htable_create(ssize_t size)
Definition: htable.c:179
#define DSB_SKIP_REPLY
Definition: dsn_buf.h:46
#define MAIL_CLASS_PUBLIC
Definition: mail_proto.h:95
#define REC_PUT_BUF(v, t, b)
Definition: record.h:43
#define PASS_ATTR(fp, name, value)
#define attr_print
Definition: attr.h:109
HTABLE_INFO ** htable_list(HTABLE *table)
Definition: htable.c:330
#define MAIL_ATTR_DSN_ORCPT
Definition: mail_proto.h:276
#define REC_TYPE_CONT
Definition: rec_type.h:58
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define REC_TYPE_TIME_FORMAT
Definition: rec_type.h:148
#define REC_TYPE_RCPT
Definition: rec_type.h:45
int forward_append(DELIVER_ATTR attr)
Definition: forward.c:216
#define FORWARD_CLEANUP_FLAGS
#define MAIL_ATTR_SASL_SENDER
Definition: mail_proto.h:158
int rec_fputs(VSTREAM *stream, int type, const char *str)
Definition: record.c:404
#define REC_TYPE_MESG
Definition: rec_type.h:56
#define STR(x)
Definition: anvil.c:518
void msg_warn(const char *fmt,...)
Definition: msg.c:215
char * key
Definition: htable.h:17
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define MAIL_ATTR_DSN_RET
Definition: mail_proto.h:274
void * htable_find(HTABLE *table, const char *key)
Definition: htable.c:227
#define MAIL_ATTR_LOG_IDENT
Definition: mail_proto.h:162
#define MAIL_ATTR_DSN_ENVID
Definition: mail_proto.h:273
#define MAIL_ATTR_LOG_CLIENT_ADDR
Definition: mail_proto.h:208
#define MAIL_ATTR_STATUS
Definition: mail_proto.h:126
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
Definition: vstream.c:1093
VSTREAM * fp
Definition: local.h:70
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
int forward_finish(DELIVER_REQUEST *request, DELIVER_ATTR attr, int cancel)
Definition: forward.c:348
DSN_BUF * why
Definition: local.h:92
const char * delivered
Definition: local.h:86
#define MAIL_ATTR_SASL_USERNAME
Definition: mail_proto.h:157
#define DSN_NOTIFY_SUCCESS
Definition: dsn_mask.h:44
const char * dsn_orcpt
#define REC_TYPE_XTRA
Definition: rec_type.h:62
#define MAIL_ATTR_LOG_CLIENT_NAME
Definition: mail_proto.h:207
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
char * queue_id
Definition: forward.c:100
#define REC_TYPE_ATTR
Definition: rec_type.h:49
#define vstream_fileno(vp)
Definition: vstream.h:115
int mark_corrupt(VSTREAM *src)
Definition: mark_corrupt.c:47
const char * sender
Definition: local.h:76
#define REC_TYPE_NORM
Definition: rec_type.h:59
#define REC_TYPE_TIME
Definition: rec_type.h:38
#define CLOSE_ON_EXEC
Definition: iostuff.h:51
RECIPIENT rcpt
Definition: local.h:79
#define MAIL_ATTR_QUEUEID
Definition: mail_proto.h:130
char * var_myhostname
Definition: mail_params.c:223
int sent(int flags, const char *id, MSG_STATS *stats, RECIPIENT *recipient, const char *relay, DSN *dsn)
Definition: sent.c:95
long offset
Definition: local.h:73
#define rec_get(fp, buf, limit)
Definition: record.h:56
#define attr_scan
Definition: attr.h:111
#define vstream_ferror(vp)
Definition: vstream.h:120
#define REC_TYPE_ORCP
Definition: rec_type.h:46
int rec_fprintf(VSTREAM *stream, int type, const char *format,...)
Definition: record.c:391
#define BLOCKING
Definition: iostuff.h:48
int local_deliver_hdr_mask
Definition: local.c:685
int close_on_exec(int fd, int on)
Definition: close_on_exec.c:49
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
#define REC_TYPE_TIME_ARG(tv)
Definition: rec_type.h:149
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
#define ATTR_FLAG_STRICT
Definition: attr.h:103
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
Definition: htable.c:212
void msg_info(const char *fmt,...)
Definition: msg.c:199