diff options
Diffstat (limited to 'src/cleanup/cleanup_extracted.c')
-rw-r--r-- | src/cleanup/cleanup_extracted.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/src/cleanup/cleanup_extracted.c b/src/cleanup/cleanup_extracted.c new file mode 100644 index 0000000..e6c2122 --- /dev/null +++ b/src/cleanup/cleanup_extracted.c @@ -0,0 +1,328 @@ +/*++ +/* NAME +/* cleanup_extracted 3 +/* SUMMARY +/* process extracted segment +/* SYNOPSIS +/* #include "cleanup.h" +/* +/* void cleanup_extracted(state, type, buf, len) +/* CLEANUP_STATE *state; +/* int type; +/* const char *buf; +/* ssize_t len; +/* DESCRIPTION +/* This module processes message records with information extracted +/* from message content, or with recipients that are stored after the +/* message content. It updates recipient records, writes extracted +/* information records to the output, and writes the queue +/* file end marker. The queue file is left in a state that +/* is suitable for Milter inspection, but the size record still +/* contains dummy values. +/* +/* Arguments: +/* .IP state +/* Queue file and message processing state. This state is updated +/* as records are processed and as errors happen. +/* .IP type +/* Record type. +/* .IP buf +/* Record content. +/* .IP len +/* Record content length. +/* 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 <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstring.h> +#include <vstream.h> +#include <mymalloc.h> +#include <nvtable.h> +#include <stringops.h> + +/* Global library. */ + +#include <cleanup_user.h> +#include <qmgr_user.h> +#include <record.h> +#include <rec_type.h> +#include <mail_params.h> +#include <mail_proto.h> +#include <dsn_mask.h> +#include <rec_attr_map.h> + +/* Application-specific. */ + +#include "cleanup.h" + +#define STR(x) vstring_str(x) + +static void cleanup_extracted_process(CLEANUP_STATE *, int, const char *, ssize_t); +static void cleanup_extracted_finish(CLEANUP_STATE *); + +/* cleanup_extracted - initialize extracted segment */ + +void cleanup_extracted(CLEANUP_STATE *state, int type, + const char *buf, ssize_t len) +{ + + /* + * Start the extracted segment. + */ + cleanup_out_string(state, REC_TYPE_XTRA, ""); + + /* + * Pass control to the actual envelope processing routine. + */ + state->action = cleanup_extracted_process; + cleanup_extracted_process(state, type, buf, len); +} + +/* cleanup_extracted_process - process one extracted envelope record */ + +void cleanup_extracted_process(CLEANUP_STATE *state, int type, + const char *buf, ssize_t len) +{ + const char *myname = "cleanup_extracted_process"; + const char *encoding; + char *attr_name; + char *attr_value; + const char *error_text; + int extra_opts; + int junk; + +#ifdef DELAY_ACTION + int defer_delay; + +#endif + + if (msg_verbose) + msg_info("extracted envelope %c %.*s", type, (int) len, buf); + + if (type == REC_TYPE_FLGS) { + /* Not part of queue file format. */ + extra_opts = atoi(buf); + if (extra_opts & ~CLEANUP_FLAG_MASK_EXTRA) + msg_warn("%s: ignoring bad extra flags: 0x%x", + state->queue_id, extra_opts); + else + state->flags |= extra_opts; + return; + } +#ifdef DELAY_ACTION + if (type == REC_TYPE_DELAY) { + /* Not part of queue file format. */ + defer_delay = atoi(buf); + if (defer_delay <= 0) + msg_warn("%s: ignoring bad delay time: %s", state->queue_id, buf); + else + state->defer_delay = defer_delay; + return; + } +#endif + + if (strchr(REC_TYPE_EXTRACT, type) == 0) { + msg_warn("%s: message rejected: " + "unexpected record type %d in extracted envelope", + state->queue_id, type); + state->errs |= CLEANUP_STAT_BAD; + return; + } + + /* + * Map DSN attribute name to pseudo record type so that we don't have to + * pollute the queue file with records that are incompatible with past + * Postfix versions. Preferably, people should be able to back out from + * an upgrade without losing mail. + */ + if (type == REC_TYPE_ATTR) { + vstring_strcpy(state->attr_buf, buf); + error_text = split_nameval(STR(state->attr_buf), &attr_name, &attr_value); + if (error_text != 0) { + msg_warn("%s: message rejected: malformed attribute: %s: %.100s", + state->queue_id, error_text, buf); + state->errs |= CLEANUP_STAT_BAD; + return; + } + /* Zero-length values are place holders for unavailable values. */ + if (*attr_value == 0) { + msg_warn("%s: spurious null attribute value for \"%s\" -- ignored", + state->queue_id, attr_name); + return; + } + if ((junk = rec_attr_map(attr_name)) != 0) { + buf = attr_value; + type = junk; + } + } + + /* + * On the transition from non-recipient records to recipient records, + * emit optional information from header/body content. + */ + if ((state->flags & CLEANUP_FLAG_INRCPT) == 0 + && strchr(REC_TYPE_EXT_RECIPIENT, type) != 0) { + if (state->filter != 0) + cleanup_out_string(state, REC_TYPE_FILT, state->filter); + if (state->redirect != 0) + cleanup_out_string(state, REC_TYPE_RDR, state->redirect); + if ((encoding = nvtable_find(state->attr, MAIL_ATTR_ENCODING)) != 0) + cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_ENCODING, encoding); + state->flags |= CLEANUP_FLAG_INRCPT; + /* Make room to append more meta records. */ + if (state->milters || cleanup_milters) { + if ((state->append_meta_pt_offset = vstream_ftell(state->dst)) < 0) + msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path); + cleanup_out_format(state, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT, 0L); + if ((state->append_meta_pt_target = vstream_ftell(state->dst)) < 0) + msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path); + } + } + + /* + * Extracted envelope recipient record processing. + */ + if (type == REC_TYPE_RCPT) { + if (state->sender == 0) { /* protect showq */ + msg_warn("%s: message rejected: envelope recipient precedes sender", + state->queue_id); + state->errs |= CLEANUP_STAT_BAD; + return; + } + if (state->orig_rcpt == 0) + state->orig_rcpt = mystrdup(buf); + cleanup_addr_recipient(state, buf); + if (cleanup_milters != 0 + && state->milters == 0 + && CLEANUP_MILTER_OK(state)) + cleanup_milter_emul_rcpt(state, cleanup_milters, state->recip); + myfree(state->orig_rcpt); + state->orig_rcpt = 0; + if (state->dsn_orcpt != 0) { + myfree(state->dsn_orcpt); + state->dsn_orcpt = 0; + } + state->dsn_notify = 0; + return; + } + if (type == REC_TYPE_DONE || type == REC_TYPE_DRCP) { + if (state->orig_rcpt != 0) { + myfree(state->orig_rcpt); + state->orig_rcpt = 0; + } + if (state->dsn_orcpt != 0) { + myfree(state->dsn_orcpt); + state->dsn_orcpt = 0; + } + state->dsn_notify = 0; + return; + } + if (type == REC_TYPE_DSN_ORCPT) { + if (state->dsn_orcpt) { + msg_warn("%s: ignoring out-of-order DSN original recipient record <%.200s>", + state->queue_id, state->dsn_orcpt); + myfree(state->dsn_orcpt); + } + state->dsn_orcpt = mystrdup(buf); + return; + } + if (type == REC_TYPE_DSN_NOTIFY) { + if (state->dsn_notify) { + msg_warn("%s: ignoring out-of-order DSN notify record <%d>", + state->queue_id, state->dsn_notify); + state->dsn_notify = 0; + } + if (!alldig(buf) || (junk = atoi(buf)) == 0 || DSN_NOTIFY_OK(junk) == 0) + msg_warn("%s: ignoring malformed dsn notify record <%.200s>", + state->queue_id, buf); + else + state->qmgr_opts |= + QMGR_READ_FLAG_FROM_DSN(state->dsn_notify = junk); + return; + } + if (type == REC_TYPE_ORCP) { + if (state->orig_rcpt != 0) { + msg_warn("%s: ignoring out-of-order original recipient record <%.200s>", + state->queue_id, buf); + myfree(state->orig_rcpt); + } + state->orig_rcpt = mystrdup(buf); + return; + } + if (type == REC_TYPE_END) { + /* Make room to append recipient. */ + if ((state->milters || cleanup_milters) + && state->append_rcpt_pt_offset < 0) { + if ((state->append_rcpt_pt_offset = vstream_ftell(state->dst)) < 0) + msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path); + cleanup_out_format(state, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT, 0L); + if ((state->append_rcpt_pt_target = vstream_ftell(state->dst)) < 0) + msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path); + } + state->flags &= ~CLEANUP_FLAG_INRCPT; + state->flags |= CLEANUP_FLAG_END_SEEN; + cleanup_extracted_finish(state); + return; + } + + /* + * Extracted envelope non-recipient record processing. + */ + if (state->flags & CLEANUP_FLAG_INRCPT) + /* Tell qmgr that recipient records are mixed with other information. */ + state->qmgr_opts |= QMGR_READ_FLAG_MIXED_RCPT_OTHER; + cleanup_out(state, type, buf, len); + return; +} + +/* cleanup_extracted_finish - complete the third message segment */ + +void cleanup_extracted_finish(CLEANUP_STATE *state) +{ + + /* + * On the way out, add the optional automatic BCC recipient. + */ + if ((state->flags & CLEANUP_FLAG_BCC_OK) + && state->recip != 0 && *var_always_bcc) + cleanup_addr_bcc(state, var_always_bcc); + + /* + * Flush non-Milter header/body_checks BCC recipients. Clear hbc_rcpt + * so that it can be used for other purposes. + */ + if (state->hbc_rcpt) { + if (CLEANUP_OUT_OK(state) && state->recip != 0) { + char **cpp; + + for (cpp = state->hbc_rcpt->argv; *cpp; cpp++) + cleanup_addr_bcc(state, *cpp); + } + argv_free(state->hbc_rcpt); + state->hbc_rcpt = 0; + } + + /* + * Terminate the extracted segment. + */ + cleanup_out_string(state, REC_TYPE_END, ""); +} |