Postfix3.3.1
cleanup_extracted.c
[詳解]
1 /*++
2 /* NAME
3 /* cleanup_extracted 3
4 /* SUMMARY
5 /* process extracted segment
6 /* SYNOPSIS
7 /* #include "cleanup.h"
8 /*
9 /* void cleanup_extracted(state, type, buf, len)
10 /* CLEANUP_STATE *state;
11 /* int type;
12 /* const char *buf;
13 /* ssize_t len;
14 /* DESCRIPTION
15 /* This module processes message records with information extracted
16 /* from message content, or with recipients that are stored after the
17 /* message content. It updates recipient records, writes extracted
18 /* information records to the output, and writes the queue
19 /* file end marker. The queue file is left in a state that
20 /* is suitable for Milter inspection, but the size record still
21 /* contains dummy values.
22 /*
23 /* Arguments:
24 /* .IP state
25 /* Queue file and message processing state. This state is updated
26 /* as records are processed and as errors happen.
27 /* .IP type
28 /* Record type.
29 /* .IP buf
30 /* Record content.
31 /* .IP len
32 /* Record content length.
33 /* LICENSE
34 /* .ad
35 /* .fi
36 /* The Secure Mailer license must be distributed with this software.
37 /* AUTHOR(S)
38 /* Wietse Venema
39 /* IBM T.J. Watson Research
40 /* P.O. Box 704
41 /* Yorktown Heights, NY 10598, USA
42 /*--*/
43 
44 /* System library. */
45 
46 #include <sys_defs.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <stdlib.h>
51 
52 /* Utility library. */
53 
54 #include <msg.h>
55 #include <vstring.h>
56 #include <vstream.h>
57 #include <mymalloc.h>
58 #include <nvtable.h>
59 #include <stringops.h>
60 
61 /* Global library. */
62 
63 #include <cleanup_user.h>
64 #include <qmgr_user.h>
65 #include <record.h>
66 #include <rec_type.h>
67 #include <mail_params.h>
68 #include <mail_proto.h>
69 #include <dsn_mask.h>
70 #include <rec_attr_map.h>
71 
72 /* Application-specific. */
73 
74 #include "cleanup.h"
75 
76 #define STR(x) vstring_str(x)
77 
78 static void cleanup_extracted_process(CLEANUP_STATE *, int, const char *, ssize_t);
79 static void cleanup_extracted_finish(CLEANUP_STATE *);
80 
81 /* cleanup_extracted - initialize extracted segment */
82 
83 void cleanup_extracted(CLEANUP_STATE *state, int type,
84  const char *buf, ssize_t len)
85 {
86 
87  /*
88  * Start the extracted segment.
89  */
91 
92  /*
93  * Pass control to the actual envelope processing routine.
94  */
95  state->action = cleanup_extracted_process;
96  cleanup_extracted_process(state, type, buf, len);
97 }
98 
99 /* cleanup_extracted_process - process one extracted envelope record */
100 
101 void cleanup_extracted_process(CLEANUP_STATE *state, int type,
102  const char *buf, ssize_t len)
103 {
104  const char *myname = "cleanup_extracted_process";
105  const char *encoding;
106  char *attr_name;
107  char *attr_value;
108  const char *error_text;
109  int extra_opts;
110  int junk;
111 
112 #ifdef DELAY_ACTION
113  int defer_delay;
114 
115 #endif
116 
117  if (msg_verbose)
118  msg_info("extracted envelope %c %.*s", type, (int) len, buf);
119 
120  if (type == REC_TYPE_FLGS) {
121  /* Not part of queue file format. */
122  extra_opts = atoi(buf);
123  if (extra_opts & ~CLEANUP_FLAG_MASK_EXTRA)
124  msg_warn("%s: ignoring bad extra flags: 0x%x",
125  state->queue_id, extra_opts);
126  else
127  state->flags |= extra_opts;
128  return;
129  }
130 #ifdef DELAY_ACTION
131  if (type == REC_TYPE_DELAY) {
132  /* Not part of queue file format. */
133  defer_delay = atoi(buf);
134  if (defer_delay <= 0)
135  msg_warn("%s: ignoring bad delay time: %s", state->queue_id, buf);
136  else
137  state->defer_delay = defer_delay;
138  return;
139  }
140 #endif
141 
142  if (strchr(REC_TYPE_EXTRACT, type) == 0) {
143  msg_warn("%s: message rejected: "
144  "unexpected record type %d in extracted envelope",
145  state->queue_id, type);
146  state->errs |= CLEANUP_STAT_BAD;
147  return;
148  }
149 
150  /*
151  * Map DSN attribute name to pseudo record type so that we don't have to
152  * pollute the queue file with records that are incompatible with past
153  * Postfix versions. Preferably, people should be able to back out from
154  * an upgrade without losing mail.
155  */
156  if (type == REC_TYPE_ATTR) {
157  vstring_strcpy(state->attr_buf, buf);
158  error_text = split_nameval(STR(state->attr_buf), &attr_name, &attr_value);
159  if (error_text != 0) {
160  msg_warn("%s: message rejected: malformed attribute: %s: %.100s",
161  state->queue_id, error_text, buf);
162  state->errs |= CLEANUP_STAT_BAD;
163  return;
164  }
165  /* Zero-length values are place holders for unavailable values. */
166  if (*attr_value == 0) {
167  msg_warn("%s: spurious null attribute value for \"%s\" -- ignored",
168  state->queue_id, attr_name);
169  return;
170  }
171  if ((junk = rec_attr_map(attr_name)) != 0) {
172  buf = attr_value;
173  type = junk;
174  }
175  }
176 
177  /*
178  * On the transition from non-recipient records to recipient records,
179  * emit optional information from header/body content.
180  */
181  if ((state->flags & CLEANUP_FLAG_INRCPT) == 0
182  && strchr(REC_TYPE_EXT_RECIPIENT, type) != 0) {
183  if (state->filter != 0)
184  cleanup_out_string(state, REC_TYPE_FILT, state->filter);
185  if (state->redirect != 0)
186  cleanup_out_string(state, REC_TYPE_RDR, state->redirect);
187  if ((encoding = nvtable_find(state->attr, MAIL_ATTR_ENCODING)) != 0)
188  cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
189  MAIL_ATTR_ENCODING, encoding);
190  state->flags |= CLEANUP_FLAG_INRCPT;
191  /* Make room to append more meta records. */
192  if (state->milters || cleanup_milters) {
193  if ((state->append_meta_pt_offset = vstream_ftell(state->dst)) < 0)
194  msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path);
196  if ((state->append_meta_pt_target = vstream_ftell(state->dst)) < 0)
197  msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path);
198  }
199  }
200 
201  /*
202  * Extracted envelope recipient record processing.
203  */
204  if (type == REC_TYPE_RCPT) {
205  if (state->sender == 0) { /* protect showq */
206  msg_warn("%s: message rejected: envelope recipient precedes sender",
207  state->queue_id);
208  state->errs |= CLEANUP_STAT_BAD;
209  return;
210  }
211  if (state->orig_rcpt == 0)
212  state->orig_rcpt = mystrdup(buf);
213  cleanup_addr_recipient(state, buf);
214  if (cleanup_milters != 0
215  && state->milters == 0
216  && CLEANUP_MILTER_OK(state))
218  myfree(state->orig_rcpt);
219  state->orig_rcpt = 0;
220  if (state->dsn_orcpt != 0) {
221  myfree(state->dsn_orcpt);
222  state->dsn_orcpt = 0;
223  }
224  state->dsn_notify = 0;
225  return;
226  }
227  if (type == REC_TYPE_DONE || type == REC_TYPE_DRCP) {
228  if (state->orig_rcpt != 0) {
229  myfree(state->orig_rcpt);
230  state->orig_rcpt = 0;
231  }
232  if (state->dsn_orcpt != 0) {
233  myfree(state->dsn_orcpt);
234  state->dsn_orcpt = 0;
235  }
236  state->dsn_notify = 0;
237  return;
238  }
239  if (type == REC_TYPE_DSN_ORCPT) {
240  if (state->dsn_orcpt) {
241  msg_warn("%s: ignoring out-of-order DSN original recipient record <%.200s>",
242  state->queue_id, state->dsn_orcpt);
243  myfree(state->dsn_orcpt);
244  }
245  state->dsn_orcpt = mystrdup(buf);
246  return;
247  }
248  if (type == REC_TYPE_DSN_NOTIFY) {
249  if (state->dsn_notify) {
250  msg_warn("%s: ignoring out-of-order DSN notify record <%d>",
251  state->queue_id, state->dsn_notify);
252  state->dsn_notify = 0;
253  }
254  if (!alldig(buf) || (junk = atoi(buf)) == 0 || DSN_NOTIFY_OK(junk) == 0)
255  msg_warn("%s: ignoring malformed dsn notify record <%.200s>",
256  state->queue_id, buf);
257  else
258  state->qmgr_opts |=
259  QMGR_READ_FLAG_FROM_DSN(state->dsn_notify = junk);
260  return;
261  }
262  if (type == REC_TYPE_ORCP) {
263  if (state->orig_rcpt != 0) {
264  msg_warn("%s: ignoring out-of-order original recipient record <%.200s>",
265  state->queue_id, buf);
266  myfree(state->orig_rcpt);
267  }
268  state->orig_rcpt = mystrdup(buf);
269  return;
270  }
271  if (type == REC_TYPE_END) {
272  /* Make room to append recipient. */
273  if ((state->milters || cleanup_milters)
274  && state->append_rcpt_pt_offset < 0) {
275  if ((state->append_rcpt_pt_offset = vstream_ftell(state->dst)) < 0)
276  msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path);
278  if ((state->append_rcpt_pt_target = vstream_ftell(state->dst)) < 0)
279  msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path);
280  }
281  state->flags &= ~CLEANUP_FLAG_INRCPT;
282  state->flags |= CLEANUP_FLAG_END_SEEN;
283  cleanup_extracted_finish(state);
284  return;
285  }
286 
287  /*
288  * Extracted envelope non-recipient record processing.
289  */
290  if (state->flags & CLEANUP_FLAG_INRCPT)
291  /* Tell qmgr that recipient records are mixed with other information. */
293  cleanup_out(state, type, buf, len);
294  return;
295 }
296 
297 /* cleanup_extracted_finish - complete the third message segment */
298 
299 void cleanup_extracted_finish(CLEANUP_STATE *state)
300 {
301 
302  /*
303  * On the way out, add the optional automatic BCC recipient.
304  */
305  if ((state->flags & CLEANUP_FLAG_BCC_OK)
306  && state->recip != 0 && *var_always_bcc)
308 
309  /*
310  * Flush non-Milter header/body_checks BCC recipients. Clear hbc_rcpt
311  * so that it can be used for other purposes.
312  */
313  if (state->hbc_rcpt) {
314  if (CLEANUP_OUT_OK(state) && state->recip != 0) {
315  char **cpp;
316 
317  for (cpp = state->hbc_rcpt->argv; *cpp; cpp++)
318  cleanup_addr_bcc(state, *cpp);
319  }
320  argv_free(state->hbc_rcpt);
321  state->hbc_rcpt = 0;
322  }
323 
324  /*
325  * Terminate the extracted segment.
326  */
327  cleanup_out_string(state, REC_TYPE_END, "");
328 }
int msg_verbose
Definition: msg.c:177
#define REC_TYPE_FILT
Definition: rec_type.h:42
#define REC_TYPE_DELAY
Definition: rec_type.h:54
char * orig_rcpt
Definition: cleanup.h:61
void myfree(void *ptr)
Definition: mymalloc.c:207
#define QMGR_READ_FLAG_MIXED_RCPT_OTHER
Definition: qmgr_user.h:25
void cleanup_out_format(CLEANUP_STATE *state, int type, const char *fmt,...)
Definition: cleanup_out.c:155
char * mystrdup(const char *str)
Definition: mymalloc.c:225
char * recip
Definition: cleanup.h:60
#define MAIL_ATTR_ENCODING
Definition: mail_proto.h:202
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
off_t vstream_ftell(VSTREAM *stream)
Definition: vstream.c:1157
off_t append_rcpt_pt_target
Definition: cleanup.h:83
char * redirect
Definition: cleanup.h:96
MILTERS * milters
Definition: cleanup.h:109
char ** argv
Definition: argv.h:20
void cleanup_extracted(CLEANUP_STATE *state, int type, const char *buf, ssize_t len)
#define CLEANUP_MILTER_OK(s)
Definition: cleanup.h:327
#define REC_TYPE_END
Definition: rec_type.h:77
int alldig(const char *string)
Definition: alldig.c:38
char * cleanup_path
Definition: cleanup_init.c:111
const char * split_nameval(char *buf, char **name, char **value)
Definition: split_nameval.c:61
#define REC_TYPE_DSN_NOTIFY
Definition: rec_type.h:73
#define CLEANUP_FLAG_INRCPT
Definition: cleanup.h:140
NVTABLE * attr
Definition: cleanup.h:91
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
off_t append_meta_pt_offset
Definition: cleanup.h:86
#define REC_TYPE_RDR
Definition: rec_type.h:52
#define REC_TYPE_DRCP
Definition: rec_type.h:47
int dsn_notify
Definition: cleanup.h:99
#define REC_TYPE_DSN_ORCPT
Definition: rec_type.h:72
#define REC_TYPE_PTR_FORMAT
Definition: rec_type.h:179
off_t append_rcpt_pt_offset
Definition: cleanup.h:82
void cleanup_milter_emul_rcpt(CLEANUP_STATE *, MILTERS *, const char *)
#define STR(x)
char * sender
Definition: cleanup.h:59
#define cleanup_addr_bcc(state, addr)
Definition: cleanup.h:304
char * dsn_orcpt
Definition: cleanup.h:100
#define REC_TYPE_RCPT
Definition: rec_type.h:45
#define CLEANUP_FLAG_MASK_EXTRA
Definition: cleanup_user.h:46
#define REC_TYPE_PTR
Definition: rec_type.h:67
void msg_warn(const char *fmt,...)
Definition: msg.c:215
ARGV * hbc_rcpt
Definition: cleanup.h:65
char * filter
Definition: cleanup.h:95
void(* action)(struct CLEANUP_STATE *, int, const char *, ssize_t)
Definition: cleanup.h:75
VSTRING * attr_buf
Definition: cleanup.h:48
char * queue_id
Definition: cleanup.h:56
int rec_attr_map(const char *attr_name)
Definition: rec_attr_map.c:39
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
VSTREAM * dst
Definition: cleanup.h:53
off_t append_meta_pt_target
Definition: cleanup.h:87
#define CLEANUP_STAT_BAD
Definition: cleanup_user.h:57
#define CLEANUP_OUT_OK(s)
Definition: cleanup.h:239
#define CLEANUP_FLAG_END_SEEN
Definition: cleanup.h:142
#define REC_TYPE_EXTRACT
Definition: rec_type.h:108
#define REC_TYPE_XTRA
Definition: rec_type.h:62
#define QMGR_READ_FLAG_FROM_DSN(x)
Definition: qmgr_user.h:26
#define DSN_NOTIFY_OK(v)
Definition: dsn_mask.h:63
#define REC_TYPE_ATTR
Definition: rec_type.h:49
#define nvtable_find(table, key)
Definition: nvtable.h:27
void cleanup_out(CLEANUP_STATE *, int, const char *, ssize_t)
Definition: cleanup_out.c:102
char * var_always_bcc
Definition: cleanup_init.c:140
void cleanup_out_string(CLEANUP_STATE *, int, const char *)
Definition: cleanup_out.c:148
MILTERS * cleanup_milters
Definition: cleanup_init.c:279
#define REC_TYPE_DONE
Definition: rec_type.h:44
#define CLEANUP_FLAG_BCC_OK
Definition: cleanup_user.h:22
#define REC_TYPE_EXT_RECIPIENT
Definition: rec_type.h:90
#define REC_TYPE_ORCP
Definition: rec_type.h:46
int qmgr_opts
Definition: cleanup.h:68
#define REC_TYPE_FLGS
Definition: rec_type.h:53
void cleanup_addr_recipient(CLEANUP_STATE *, const char *)
Definition: cleanup_addr.c:190
void msg_info(const char *fmt,...)
Definition: msg.c:199