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