8
8
/* #include <smtp_reuse.h>
10
/* void smtp_save_session(state)
13
/* SMTP_SESSION *smtp_reuse_domain(state, lookup_mx, domain, port)
19
/* SMTP_SESSION *smtp_reuse_addr(state, addr, port)
10
/* void smtp_save_session(state, name_key_flags, endp_key_flags)
12
/* int name_key_flags;
13
/* int endp_key_flags;
15
/* SMTP_SESSION *smtp_reuse_nexthop(state, name_key_flags)
17
/* int name_key_flags;
19
/* SMTP_SESSION *smtp_reuse_addr(state, endp_key_flags)
21
/* int endp_key_flags;
24
23
/* This module implements the SMTP client specific interface to
25
24
/* the generic session cache infrastructure.
27
/* Each cached connection identifier includes the name of the
28
/* mail delivery service. Thus, cached connections are not
29
/* shared between different services.
26
/* A cached connection is closed when the TLS policy requires
27
/* that TLS is enabled.
31
29
/* smtp_save_session() stores the current session under the
32
30
/* next-hop logical destination (if available) and under the
33
31
/* remote server address. The SMTP_SESSION object is destroyed.
35
/* smtp_reuse_domain() looks up a cached session by its logical
33
/* smtp_reuse_nexthop() looks up a cached session by its logical
36
34
/* destination, and verifies that the session is still alive.
37
/* The restored session information includes the "best MX" bit.
35
/* The restored session information includes the "best MX" bit
36
/* and overrides the iterator dest, host and addr fields.
38
37
/* The result is null in case of failure.
40
39
/* smtp_reuse_addr() looks up a cached session by its server
41
40
/* address, and verifies that the session is still alive.
42
/* This operation is disabled when the legacy tls_per_site
43
/* or smtp_sasl_password_maps features are enabled.
41
/* The restored session information does not include the "best
42
/* MX" bit, and does not override the iterator dest, host and
44
44
/* The result is null in case of failure.
48
48
/* SMTP client state, including the current session, the original
49
49
/* next-hop domain, etc.
51
/* Whether or not the domain is subject to MX lookup.
53
/* Domain name or bare numerical address.
55
/* The remote server address as printable text.
57
/* The remote server port, network byte order.
51
/* Explicit declaration of context that should be used to look
52
/* up a cached connection by its logical destination.
53
/* See smtp_key(3) for details.
55
/* Explicit declaration of context that should be used to look
56
/* up a cached connection by its server address.
57
/* See smtp_key(3) for details.
95
95
#include <smtp_reuse.h>
98
* We encode the MX lookup/A lookup method into the name under which SMTP
99
* session information is cached. The following macros serve to make the
100
* remainder of the code less obscure.
98
* Key field delimiter, and place holder field value for
99
* unavailable/inapplicable information.
102
#define NO_MX_LOOKUP 0
104
#define SMTP_SCACHE_LABEL(mx_lookup_flag) \
105
((mx_lookup_flag) ? "%s:%s:%u" : "%s:[%s]:%u")
101
#define SMTP_REUSE_KEY_DELIM_NA "\n*"
107
103
/* smtp_save_session - save session under next-hop name and server address */
109
void smtp_save_session(SMTP_STATE *state)
105
void smtp_save_session(SMTP_STATE *state, int name_key_flags,
111
108
SMTP_SESSION *session = state->session;
115
112
* Encode the next-hop logical destination, if available. Reuse storage
116
113
* that is also used for cache lookup queries.
118
* Note: if the label needs to be made more specific (with e.g., SASL login
119
* information), just append the text with vstring_sprintf_append().
121
115
if (HAVE_NEXTHOP_STATE(state))
122
vstring_sprintf(state->dest_label,
123
SMTP_SCACHE_LABEL(state->nexthop_lookup_mx),
124
state->service, state->nexthop_domain,
125
ntohs(state->nexthop_port));
116
smtp_key_prefix(state->dest_label, SMTP_REUSE_KEY_DELIM_NA,
117
state->iterator, name_key_flags);
128
120
* Encode the physical endpoint name. Reuse storage that is also used for
129
121
* cache lookup queries.
131
* Note: if the label needs to be made more specific (with e.g., SASL login
132
* information), just append the text with vstring_sprintf_append().
134
vstring_sprintf(state->endp_label,
135
SMTP_SCACHE_LABEL(NO_MX_LOOKUP),
136
state->service, session->addr, ntohs(session->port));
123
smtp_key_prefix(state->endp_label, SMTP_REUSE_KEY_DELIM_NA,
124
state->iterator, endp_key_flags);
139
127
* Passivate the SMTP_SESSION object, destroying the object in the
167
155
const char *label)
169
157
const char *myname = "smtp_reuse_common";
158
SMTP_ITERATOR *iter = state->iterator;
170
159
SMTP_SESSION *session;
162
* Can't happen. Both smtp_reuse_nexthop() and smtp_reuse_addr() decline
163
* the request when the TLS policy is not TLS_LEV_NONE.
166
if (state->tls->level > TLS_LEV_NONE)
167
msg_panic("%s: unexpected plain-text cached session to %s",
173
172
* Re-activate the SMTP_SESSION object.
175
session = smtp_session_activate(fd, state->dest_prop, state->endp_prop);
174
session = smtp_session_activate(fd, state->iterator, state->dest_prop,
176
176
if (session == 0) {
177
177
msg_warn("%s: bad cached session attribute for %s", myname, label);
178
178
(void) close(fd);
181
181
state->session = session;
182
182
session->state = state;
187
* Cached connections are always plaintext. They must never be reused when
188
* TLS encryption is required.
190
* As long as we support the legacy smtp_tls_per_site feature, we must
191
* search the connection cache before making TLS policy decisions. This
192
* is because the policy can depend on the server name. For example, a
193
* site could have a global policy that requires encryption, with
194
* per-server exceptions that allow plaintext.
196
* With the newer smtp_tls_policy_maps feature, the policy depends on the
197
* next-hop destination only. We can avoid unnecessary connection cache
198
* lookups, because we can compute the TLS policy much earlier.
201
if (session->tls_level >= TLS_LEV_ENCRYPT) {
203
msg_info("%s: skipping plain-text cached session to %s",
205
smtp_quit(state); /* Close politely */
206
smtp_session_free(session); /* And avoid leaks */
207
return (state->session = 0);
184
session->tls = state->tls; /* TEMPORARY */
226
202
* Update the list of used cached addresses.
228
htable_enter(state->cache_used, session->addr, (char *) 0);
204
htable_enter(state->cache_used, STR(iter->addr), (char *) 0);
230
206
return (session);
233
/* smtp_reuse_domain - reuse session cached under domain name */
209
/* smtp_reuse_nexthop - reuse session cached under nexthop name */
235
SMTP_SESSION *smtp_reuse_domain(SMTP_STATE *state, int lookup_mx,
236
const char *domain, unsigned port)
211
SMTP_SESSION *smtp_reuse_nexthop(SMTP_STATE *state, int name_key_flags)
238
213
SMTP_SESSION *session;
217
* Don't look up an existing plaintext connection when a new connection
218
* would (try to) use TLS.
221
if (state->tls->level > TLS_LEV_NONE)
242
226
* Look up the session by its logical name.
244
* Note: if the label needs to be made more specific (with e.g., SASL login
245
* information), just append the text with vstring_sprintf_append().
247
vstring_sprintf(state->dest_label, SMTP_SCACHE_LABEL(lookup_mx),
248
state->service, domain, ntohs(port));
228
smtp_key_prefix(state->dest_label, SMTP_REUSE_KEY_DELIM_NA,
229
state->iterator, name_key_flags);
249
230
if ((fd = scache_find_dest(smtp_scache, STR(state->dest_label),
250
231
state->dest_prop, state->endp_prop)) < 0)
261
242
/* smtp_reuse_addr - reuse session cached under numerical address */
263
SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, const char *addr,
244
SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, int endp_key_flags)
266
246
SMTP_SESSION *session;
270
* XXX Disable connection cache lookup by server IP address when the
271
* tls_per_site policy or smtp_sasl_password_maps features are enabled.
272
* This connection may have been created under a different hostname that
273
* resolves to the same IP address. We don't want to use the wrong SASL
274
* credentials or the wrong TLS policy.
250
* Don't look up an existing plaintext connection when a new connection
251
* would (try to) use TLS.
276
if ((var_smtp_tls_per_site && *var_smtp_tls_per_site)
277
|| (var_smtp_tls_policy && *var_smtp_tls_policy))
254
if (state->tls->level > TLS_LEV_NONE)
281
259
* Look up the session by its IP address. This means that we have no
282
260
* destination-to-address binding properties.
284
* Note: if the label needs to be made more specific (with e.g., SASL login
285
* information), just append the text with vstring_sprintf_append().
287
vstring_sprintf(state->endp_label, SMTP_SCACHE_LABEL(NO_MX_LOOKUP),
288
state->service, addr, ntohs(port));
262
smtp_key_prefix(state->endp_label, SMTP_REUSE_KEY_DELIM_NA,
263
state->iterator, endp_key_flags);
289
264
if ((fd = scache_find_endp(smtp_scache, STR(state->endp_label),
290
265
state->endp_prop)) < 0)
299
274
session = smtp_reuse_common(state, fd, STR(state->endp_label));
302
* XXX What if hostnames don't match (addr->name versus session->name),
303
* or if the SASL login name for this host does not match the SASL login
304
* name that was used when opening this session? If something depends
305
* critically on such information being identical, then that information
306
* should be included in the logical and physical labels under which a
309
276
return (session);