summaryrefslogtreecommitdiffstats
path: root/src/cleanup/cleanup_out_recipient.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cleanup/cleanup_out_recipient.c')
-rw-r--r--src/cleanup/cleanup_out_recipient.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/cleanup/cleanup_out_recipient.c b/src/cleanup/cleanup_out_recipient.c
new file mode 100644
index 0000000..5e965fa
--- /dev/null
+++ b/src/cleanup/cleanup_out_recipient.c
@@ -0,0 +1,266 @@
+/*++
+/* NAME
+/* cleanup_out_recipient 3
+/* SUMMARY
+/* envelope recipient output filter
+/* SYNOPSIS
+/* #include "cleanup.h"
+/*
+/* void cleanup_out_recipient(state, dsn_orig_recipient,
+/* dsn_notify, orig_recipient,
+/* recipient)
+/* CLEANUP_STATE *state;
+/* const char *dsn_orig_recipient;
+/* const char *dsn_notify;
+/* const char *orig_recipient;
+/* const char *recipient;
+/* DESCRIPTION
+/* This module implements an envelope recipient output filter.
+/*
+/* cleanup_out_recipient() performs virtual table expansion
+/* and recipient duplicate filtering, and appends the
+/* resulting recipients to the output stream. It also
+/* generates DSN SUCCESS notifications.
+/*
+/* Arguments:
+/* .IP state
+/* Cleanup server state.
+/* .IP dsn_orig_recipient
+/* DSN original recipient information.
+/* .IP dsn_notify
+/* DSN notify flags.
+/* .IP orig_recipient
+/* Envelope recipient as received by Postfix.
+/* .IP recipient
+/* Envelope recipient as rewritten by Postfix.
+/* CONFIGURATION
+/* .ad
+/* .fi
+/* .IP enable_original_recipient
+/* Enable orig_recipient support.
+/* .IP local_duplicate_filter_limit
+/* Upper bound to the size of the recipient duplicate filter.
+/* Zero means no limit; this may cause the mail system to
+/* become stuck.
+/* .IP virtual_alias_maps
+/* list of virtual address lookup tables.
+/* 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
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <argv.h>
+#include <msg.h>
+
+/* Global library. */
+
+#include <been_here.h>
+#include <mail_params.h>
+#include <rec_type.h>
+#include <ext_prop.h>
+#include <cleanup_user.h>
+#include <dsn_mask.h>
+#include <recipient_list.h>
+#include <dsn.h>
+#include <trace.h>
+#include <verify.h>
+#include <mail_queue.h> /* cleanup_trace_path */
+#include <mail_proto.h>
+#include <msg_stats.h>
+
+/* Application-specific. */
+
+#include "cleanup.h"
+
+/* cleanup_trace_append - update trace logfile */
+
+static void cleanup_trace_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
+ DSN *dsn)
+{
+ MSG_STATS stats;
+
+ if (cleanup_trace_path == 0) {
+ cleanup_trace_path = vstring_alloc(10);
+ mail_queue_path(cleanup_trace_path, MAIL_QUEUE_TRACE,
+ state->queue_id);
+ }
+ if (trace_append(BOUNCE_FLAG_CLEAN, state->queue_id,
+ CLEANUP_MSG_STATS(&stats, state),
+ rcpt, "none", dsn) != 0) {
+ msg_warn("%s: trace logfile update error", state->queue_id);
+ state->errs |= CLEANUP_STAT_WRITE;
+ }
+}
+
+/* cleanup_verify_append - update verify daemon */
+
+static void cleanup_verify_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
+ DSN *dsn, int verify_status)
+{
+ MSG_STATS stats;
+
+ if (verify_append(state->queue_id, CLEANUP_MSG_STATS(&stats, state),
+ rcpt, "none", dsn, verify_status) != 0) {
+ msg_warn("%s: verify service update error", state->queue_id);
+ state->errs |= CLEANUP_STAT_WRITE;
+ }
+}
+
+/* cleanup_out_recipient - envelope recipient output filter */
+
+void cleanup_out_recipient(CLEANUP_STATE *state,
+ const char *dsn_orcpt,
+ int dsn_notify,
+ const char *orcpt,
+ const char *recip)
+{
+ ARGV *argv;
+ char **cpp;
+
+ /*
+ * XXX Not elegant, but eliminates complexity in the record reading loop.
+ */
+ if (dsn_orcpt == 0)
+ dsn_orcpt = "";
+
+ /*
+ * Distinguish between different original recipient addresses that map
+ * onto the same mailbox. The recipient will use our original recipient
+ * message header to figure things out.
+ *
+ * Postfix 2.2 compatibility: when ignoring differences in Postfix original
+ * recipient information, also ignore differences in DSN attributes. We
+ * do, however, keep the DSN attributes of the recipient that survives
+ * duplicate elimination.
+ */
+#define STREQ(x, y) (strcmp((x), (y)) == 0)
+
+ if ((state->flags & CLEANUP_FLAG_MAP_OK) == 0
+ || cleanup_virt_alias_maps == 0) {
+ /* Matches been_here_drop{,_fixed}() calls cleanup_del_rcpt(). */
+ if ((var_enable_orcpt ?
+ been_here(state->dups, "%s\n%d\n%s\n%s",
+ dsn_orcpt, dsn_notify, orcpt, recip) :
+ been_here_fixed(state->dups, recip)) == 0) {
+ if (dsn_notify)
+ cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d",
+ MAIL_ATTR_DSN_NOTIFY, dsn_notify);
+ if (*dsn_orcpt)
+ cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_DSN_ORCPT, dsn_orcpt);
+ cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
+ cleanup_out_string(state, REC_TYPE_RCPT, recip);
+ state->rcpt_count++;
+ }
+ }
+
+ /*
+ * XXX DSN. RFC 3461 gives us three options for multi-recipient aliases
+ * (we're treating single recipient aliases as a special case of
+ * multi-recipient aliases, one argument being that it is none of the
+ * sender's business).
+ *
+ * (a) Don't propagate ENVID, NOTIFY, RET, or ORCPT. If NOTIFY specified
+ * SUCCESS, send a "relayed" DSN.
+ *
+ * (b) Propagate ENVID, (NOTIFY minus SUCCESS), RET, and ORCPT. If NOTIFY
+ * specified SUCCESS, send an "expanded" DSN.
+ *
+ * (c) Propagate ENVID, NOTIFY, RET, and ORCPT to one recipient only. Send
+ * no DSN.
+ *
+ * In all three cases we are modifying at least one NOTIFY value. Either we
+ * have to record explicit dsn_notify records, or we must not allow the
+ * use of a per-message non-default NOTIFY value that applies to all
+ * recipient records.
+ *
+ * Alternatives (a) and (c) require that we store explicit per-recipient RET
+ * and ENVID records, at least for the recipients that are excluded from
+ * RET and ENVID propagation. This means storing explicit ENVID records
+ * to indicate that the information does not exist. All this makes
+ * alternative (b) more and more attractive. It is no surprise that we
+ * use (b) here and in the local delivery agent.
+ *
+ * In order to generate a SUCCESS notification from the cleanup server we
+ * have to write the trace logfile record now. We're NOT going to flush
+ * the trace file from the cleanup server; if we need to write bounce
+ * logfile records, and the bounce service fails, we must be able to
+ * cancel the entire cleanup request including any success or failure
+ * notifications. The queue manager will flush the trace (and bounce)
+ * logfile, possibly after it has generated its own success or failure
+ * notification records.
+ *
+ * Postfix 2.2 compatibility: when ignoring differences in Postfix original
+ * recipient information, also ignore differences in DSN attributes. We
+ * do, however, keep the DSN attributes of the recipient that survives
+ * duplicate elimination.
+ *
+ * In the case of a verify(8) request for a one-to-many alias, declare the
+ * alias address as "deliverable". Do not verify the individual addresses
+ * in the expansion because that results in multiple verify(8) updates
+ * for one verify(8) request.
+ *
+ * Multiple verify(8) updates for one verify(8) request would overwrite
+ * each other's status, and if the last status update is "undeliverable",
+ * then the whole alias is flagged as undeliverable.
+ */
+ else {
+ RECIPIENT rcpt;
+ DSN dsn;
+
+ argv = cleanup_map1n_internal(state, recip, cleanup_virt_alias_maps,
+ cleanup_ext_prop_mask & EXT_PROP_VIRTUAL);
+ if (argv->argc > 1 && (state->tflags & DEL_REQ_FLAG_MTA_VRFY)) {
+ (void) DSN_SIMPLE(&dsn, "2.0.0", "aliased to multiple recipients");
+ dsn.action = "deliverable";
+ RECIPIENT_ASSIGN(&rcpt, 0, dsn_orcpt, dsn_notify, orcpt, recip);
+ cleanup_verify_append(state, &rcpt, &dsn, DEL_RCPT_STAT_OK);
+ argv_free(argv);
+ return;
+ }
+ if ((dsn_notify & DSN_NOTIFY_SUCCESS)
+ && (argv->argc > 1 || strcmp(recip, argv->argv[0]) != 0)) {
+ (void) DSN_SIMPLE(&dsn, "2.0.0", "alias expanded");
+ dsn.action = "expanded";
+ RECIPIENT_ASSIGN(&rcpt, 0, dsn_orcpt, dsn_notify, orcpt, recip);
+ cleanup_trace_append(state, &rcpt, &dsn);
+ dsn_notify = (dsn_notify == DSN_NOTIFY_SUCCESS ? DSN_NOTIFY_NEVER :
+ dsn_notify & ~DSN_NOTIFY_SUCCESS);
+ }
+ for (cpp = argv->argv; *cpp; cpp++) {
+ if ((var_enable_orcpt ?
+ been_here(state->dups, "%s\n%d\n%s\n%s",
+ dsn_orcpt, dsn_notify, orcpt, *cpp) :
+ been_here_fixed(state->dups, *cpp)) == 0) {
+ if (dsn_notify)
+ cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d",
+ MAIL_ATTR_DSN_NOTIFY, dsn_notify);
+ if (*dsn_orcpt)
+ cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_DSN_ORCPT, dsn_orcpt);
+ cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
+ cleanup_out_string(state, REC_TYPE_RCPT, *cpp);
+ state->rcpt_count++;
+ }
+ }
+ argv_free(argv);
+ }
+}