summaryrefslogtreecommitdiffstats
path: root/src/local/unknown.c
blob: 96443e178f1c6fc7561bcf3128a78b785c3fe96e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
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)));
}