1/* $NetBSD: unknown.c,v 1.8 2022/10/08 16:12:46 christos Exp $ */ 2 3/*++ 4/* NAME 5/* unknown 3 6/* SUMMARY 7/* delivery of unknown recipients 8/* SYNOPSIS 9/* #include "local.h" 10/* 11/* int deliver_unknown(state, usr_attr) 12/* LOCAL_STATE state; 13/* USER_ATTR usr_attr; 14/* DESCRIPTION 15/* deliver_unknown() delivers a message for unknown recipients. 16/* .IP \(bu 17/* If an alternative message transport is specified via the 18/* fallback_transport parameter, delivery is delegated to the 19/* named transport. 20/* .IP \(bu 21/* If an alternative address is specified via the luser_relay 22/* configuration parameter, mail is forwarded to that address. 23/* .IP \(bu 24/* Otherwise the recipient is bounced. 25/* .PP 26/* The luser_relay parameter is subjected to $name expansion of 27/* the standard message attributes: $user, $home, $shell, $domain, 28/* $recipient, $mailbox, $extension, $recipient_delimiter, not 29/* all of which actually make sense. 30/* 31/* Arguments: 32/* .IP state 33/* Message delivery attributes (sender, recipient etc.). 34/* Attributes describing alias, include or forward expansion. 35/* A table with the results from expanding aliases or lists. 36/* A table with delivered-to: addresses taken from the message. 37/* .IP usr_attr 38/* Attributes describing user rights and environment. 39/* DIAGNOSTICS 40/* The result status is non-zero when delivery should be tried again. 41/* LICENSE 42/* .ad 43/* .fi 44/* The Secure Mailer license must be distributed with this software. 45/* AUTHOR(S) 46/* Wietse Venema 47/* IBM T.J. Watson Research 48/* P.O. Box 704 49/* Yorktown Heights, NY 10598, USA 50/* 51/* Wietse Venema 52/* Google, Inc. 53/* 111 8th Avenue 54/* New York, NY 10011, USA 55/*--*/ 56 57/* System library. */ 58 59#include <sys_defs.h> 60#include <string.h> 61 62#ifdef STRCASECMP_IN_STRINGS_H 63#include <strings.h> 64#endif 65 66/* Utility library. */ 67 68#include <msg.h> 69#include <stringops.h> 70#include <mymalloc.h> 71#include <vstring.h> 72 73/* Global library. */ 74 75#include <been_here.h> 76#include <mail_params.h> 77#include <mail_proto.h> 78#include <bounce.h> 79#include <mail_addr.h> 80#include <sent.h> 81#include <deliver_pass.h> 82#include <defer.h> 83#include <canon_addr.h> 84 85/* Application-specific. */ 86 87#include "local.h" 88 89#define STREQ(x,y) (strcasecmp((x),(y)) == 0) 90 91/* deliver_unknown - delivery for unknown recipients */ 92 93int deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr) 94{ 95 const char *myname = "deliver_unknown"; 96 int status; 97 VSTRING *expand_luser; 98 VSTRING *canon_luser; 99 static MAPS *transp_maps; 100 const char *map_transport; 101 102 /* 103 * Make verbose logging easier to understand. 104 */ 105 state.level++; 106 if (msg_verbose) 107 MSG_LOG_STATE(myname, state); 108 109 /* 110 * DUPLICATE/LOOP ELIMINATION 111 * 112 * Don't deliver the same user twice. 113 */ 114 if (been_here(state.dup_filter, "%s %s", myname, state.msg_attr.local)) 115 return (0); 116 117 /* 118 * The fall-back transport specifies a delivery mechanism that handles 119 * users not found in the aliases or UNIX passwd databases. 120 */ 121 if (*var_fbck_transp_maps && transp_maps == 0) 122 transp_maps = maps_create(VAR_FBCK_TRANSP_MAPS, var_fbck_transp_maps, 123 DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB 124 | DICT_FLAG_UTF8_REQUEST); 125 /* The -1 is a hint for the down-stream deliver_completed() function. */ 126 if (transp_maps 127 && (map_transport = maps_find(transp_maps, state.msg_attr.user, 128 DICT_FLAG_NONE)) != 0) { 129 state.msg_attr.rcpt.offset = -1L; 130 return (deliver_pass(MAIL_CLASS_PRIVATE, map_transport, 131 state.request, &state.msg_attr.rcpt)); 132 } else if (transp_maps && transp_maps->error != 0) { 133 /* Details in the logfile. */ 134 dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure"); 135 return (defer_append(BOUNCE_FLAGS(state.request), 136 BOUNCE_ATTR(state.msg_attr))); 137 } 138 if (*var_fallback_transport) { 139 state.msg_attr.rcpt.offset = -1L; 140 return (deliver_pass(MAIL_CLASS_PRIVATE, var_fallback_transport, 141 state.request, &state.msg_attr.rcpt)); 142 } 143 144 /* 145 * Subject the luser_relay address to $name expansion, disable 146 * propagation of unmatched address extension, and re-inject the address 147 * into the delivery machinery. Do not give special treatment to "|stuff" 148 * or /stuff. 149 */ 150 if (*var_luser_relay) { 151 state.msg_attr.unmatched = 0; 152 expand_luser = vstring_alloc(100); 153 canon_luser = vstring_alloc(100); 154 local_expand(expand_luser, var_luser_relay, &state, &usr_attr, (void *) 0); 155 /* In case luser_relay specifies a domain-less address. */ 156 canon_addr_external(canon_luser, vstring_str(expand_luser)); 157 /* Assumes that the address resolver won't change the address. */ 158 if (STREQ(vstring_str(canon_luser), state.msg_attr.rcpt.address)) { 159 dsb_simple(state.msg_attr.why, "5.1.1", 160 "unknown user: \"%s\"", state.msg_attr.user); 161 status = bounce_append(BOUNCE_FLAGS(state.request), 162 BOUNCE_ATTR(state.msg_attr)); 163 } else { 164 status = deliver_resolve_addr(state, usr_attr, STR(expand_luser)); 165 } 166 vstring_free(canon_luser); 167 vstring_free(expand_luser); 168 return (status); 169 } 170 171 /* 172 * If no alias was found for a required reserved name, toss the message 173 * into the bit bucket, and issue a warning instead. 174 */ 175 if (STREQ(state.msg_attr.user, MAIL_ADDR_MAIL_DAEMON) 176 || STREQ(state.msg_attr.user, MAIL_ADDR_POSTMASTER)) { 177 msg_warn("required alias not found: %s", state.msg_attr.user); 178 dsb_simple(state.msg_attr.why, "2.0.0", "discarded"); 179 return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr))); 180 } 181 182 /* 183 * Bounce the message when no luser relay is specified. 184 */ 185 dsb_simple(state.msg_attr.why, "5.1.1", 186 "unknown user: \"%s\"", state.msg_attr.user); 187 return (bounce_append(BOUNCE_FLAGS(state.request), 188 BOUNCE_ATTR(state.msg_attr))); 189} 190