summaryrefslogtreecommitdiffstats
path: root/src/local/unknown.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/local/unknown.c')
-rw-r--r--src/local/unknown.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/local/unknown.c b/src/local/unknown.c
new file mode 100644
index 0000000..96443e1
--- /dev/null
+++ b/src/local/unknown.c
@@ -0,0 +1,187 @@
+/*++
+/* NAME
+/* unknown 3
+/* SUMMARY
+/* delivery of unknown recipients
+/* SYNOPSIS
+/* #include "local.h"
+/*
+/* int deliver_unknown(state, usr_attr)
+/* LOCAL_STATE state;
+/* USER_ATTR usr_attr;
+/* DESCRIPTION
+/* deliver_unknown() delivers a message for unknown recipients.
+/* .IP \(bu
+/* If an alternative message transport is specified via the
+/* fallback_transport parameter, delivery is delegated to the
+/* named transport.
+/* .IP \(bu
+/* If an alternative address is specified via the luser_relay
+/* configuration parameter, mail is forwarded to that address.
+/* .IP \(bu
+/* Otherwise the recipient is bounced.
+/* .PP
+/* The luser_relay parameter is subjected to $name expansion of
+/* the standard message attributes: $user, $home, $shell, $domain,
+/* $recipient, $mailbox, $extension, $recipient_delimiter, not
+/* all of which actually make sense.
+/*
+/* Arguments:
+/* .IP state
+/* Message delivery attributes (sender, recipient etc.).
+/* Attributes describing alias, include or forward expansion.
+/* A table with the results from expanding aliases or lists.
+/* A table with delivered-to: addresses taken from the message.
+/* .IP usr_attr
+/* Attributes describing user rights and environment.
+/* DIAGNOSTICS
+/* The result status is non-zero when delivery should be tried again.
+/* 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>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <stringops.h>
+#include <mymalloc.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <been_here.h>
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <bounce.h>
+#include <mail_addr.h>
+#include <sent.h>
+#include <deliver_pass.h>
+#include <defer.h>
+#include <canon_addr.h>
+
+/* Application-specific. */
+
+#include "local.h"
+
+#define STREQ(x,y) (strcasecmp((x),(y)) == 0)
+
+/* deliver_unknown - delivery for unknown recipients */
+
+int deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr)
+{
+ const char *myname = "deliver_unknown";
+ int status;
+ VSTRING *expand_luser;
+ VSTRING *canon_luser;
+ static MAPS *transp_maps;
+ const char *map_transport;
+
+ /*
+ * Make verbose logging easier to understand.
+ */
+ state.level++;
+ if (msg_verbose)
+ MSG_LOG_STATE(myname, state);
+
+ /*
+ * DUPLICATE/LOOP ELIMINATION
+ *
+ * Don't deliver the same user twice.
+ */
+ if (been_here(state.dup_filter, "%s %s", myname, state.msg_attr.local))
+ return (0);
+
+ /*
+ * The fall-back transport specifies a delivery mechanism that handles
+ * users not found in the aliases or UNIX passwd databases.
+ */
+ if (*var_fbck_transp_maps && transp_maps == 0)
+ transp_maps = maps_create(VAR_FBCK_TRANSP_MAPS, var_fbck_transp_maps,
+ DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB
+ | DICT_FLAG_UTF8_REQUEST);
+ /* The -1 is a hint for the down-stream deliver_completed() function. */
+ if (transp_maps
+ && (map_transport = maps_find(transp_maps, state.msg_attr.user,
+ DICT_FLAG_NONE)) != 0) {
+ state.msg_attr.rcpt.offset = -1L;
+ return (deliver_pass(MAIL_CLASS_PRIVATE, map_transport,
+ state.request, &state.msg_attr.rcpt));
+ } else if (transp_maps && transp_maps->error != 0) {
+ /* Details in the logfile. */
+ dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure");
+ return (defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr)));
+ }
+ if (*var_fallback_transport) {
+ state.msg_attr.rcpt.offset = -1L;
+ return (deliver_pass(MAIL_CLASS_PRIVATE, var_fallback_transport,
+ state.request, &state.msg_attr.rcpt));
+ }
+
+ /*
+ * Subject the luser_relay address to $name expansion, disable
+ * propagation of unmatched address extension, and re-inject the address
+ * into the delivery machinery. Do not give special treatment to "|stuff"
+ * or /stuff.
+ */
+ if (*var_luser_relay) {
+ state.msg_attr.unmatched = 0;
+ expand_luser = vstring_alloc(100);
+ canon_luser = vstring_alloc(100);
+ local_expand(expand_luser, var_luser_relay, &state, &usr_attr, (void *) 0);
+ /* In case luser_relay specifies a domain-less address. */
+ canon_addr_external(canon_luser, vstring_str(expand_luser));
+ /* Assumes that the address resolver won't change the address. */
+ if (STREQ(vstring_str(canon_luser), state.msg_attr.rcpt.address)) {
+ dsb_simple(state.msg_attr.why, "5.1.1",
+ "unknown user: \"%s\"", state.msg_attr.user);
+ status = bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr));
+ } else {
+ status = deliver_resolve_addr(state, usr_attr, STR(expand_luser));
+ }
+ vstring_free(canon_luser);
+ vstring_free(expand_luser);
+ return (status);
+ }
+
+ /*
+ * If no alias was found for a required reserved name, toss the message
+ * into the bit bucket, and issue a warning instead.
+ */
+ if (STREQ(state.msg_attr.user, MAIL_ADDR_MAIL_DAEMON)
+ || STREQ(state.msg_attr.user, MAIL_ADDR_POSTMASTER)) {
+ msg_warn("required alias not found: %s", state.msg_attr.user);
+ dsb_simple(state.msg_attr.why, "2.0.0", "discarded");
+ return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)));
+ }
+
+ /*
+ * Bounce the message when no luser relay is specified.
+ */
+ dsb_simple(state.msg_attr.why, "5.1.1",
+ "unknown user: \"%s\"", state.msg_attr.user);
+ return (bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr)));
+}