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