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
deliver_unknown(LOCAL_STATE state,USER_ATTR usr_attr)93 int 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