5
/* SMTP session cache glue
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)
24
/* This module implements the SMTP client specific interface to
25
/* the generic session cache infrastructure.
27
/* smtp_save_session() stores the current session under the
28
/* next-hop logical destination (if available) and under the
29
/* remote server address. The SMTP_SESSION object is destroyed.
31
/* smtp_reuse_domain() looks up a cached session by its logical
32
/* destination, and verifies that the session is still alive.
33
/* The restored session information includes the "best MX" bit.
34
/* The result is null in case of failure.
36
/* smtp_reuse_addr() looks up a cached session by its server
37
/* address, and verifies that the session is still alive.
38
/* The result is null in case of failure.
42
/* SMTP client state, including the current session, the original
43
/* next-hop domain, etc.
45
/* Whether or not the domain is subject to MX lookup.
47
/* Domain name or bare numerical address.
49
/* The remote server name and address.
51
/* The remote server port, network byte order.
55
/* The Secure Mailer license must be distributed with this software.
58
/* IBM T.J. Watson Research
60
/* Yorktown Heights, NY 10598, USA
66
#include <sys/socket.h>
67
#include <netinet/in.h>
68
#include <arpa/inet.h>
72
/* Utility library. */
79
#include <stringops.h>
84
#include <mail_params.h>
86
/* Application-specific. */
89
#include <smtp_reuse.h>
92
* We encode the MX lookup/A lookup method into the name under which SMTP
93
* session information is cached. The following macros serve to make the
94
* remainder of the code less obscure.
96
#define NO_MX_LOOKUP 0
98
#define SMTP_SCACHE_LABEL(mx_lookup_flag) \
99
((mx_lookup_flag) ? "%s:%s:%u" : "%s:[%s]:%u")
101
#define STR(x) vstring_str(x)
103
/* smtp_save_session - save session under next-hop name and server address */
105
void smtp_save_session(SMTP_STATE *state)
107
SMTP_SESSION *session = state->session;
111
* Encode the next-hop logical destination, if available. Reuse storage
112
* that is also used for cache lookup queries.
114
* Note: if the label needs to be made more specific (with e.g., SASL login
115
* information), just append the text with vstring_sprintf_append().
117
if (HAVE_NEXTHOP_STATE(state))
118
vstring_sprintf(state->dest_label,
119
SMTP_SCACHE_LABEL(state->nexthop_lookup_mx),
120
state->service, state->nexthop_domain,
121
ntohs(state->nexthop_port));
124
* Encode the physical endpoint name. Reuse storage that is also used for
125
* cache lookup queries.
127
* Note: if the label needs to be made more specific (with e.g., SASL login
128
* information), just append the text with vstring_sprintf_append().
130
vstring_sprintf(state->endp_label,
131
SMTP_SCACHE_LABEL(NO_MX_LOOKUP),
132
state->service, session->addr, ntohs(session->port));
135
* Passivate the SMTP_SESSION object, destroying the object in the
136
* process. Reuse storage that is also used for cache lookup results.
138
fd = smtp_session_passivate(session, state->dest_prop, state->endp_prop);
142
* Save the session under the next-hop name, if available.
144
* XXX The logical to physical binding can be kept for as long as the DNS
145
* allows us to (but that could result in the caching of lots of unused
146
* bindings). The session should be idle for no more than 30 seconds or
149
if (HAVE_NEXTHOP_STATE(state))
150
scache_save_dest(smtp_scache, var_smtp_cache_conn, STR(state->dest_label),
151
STR(state->dest_prop), STR(state->endp_label));
154
* Save every good session under its physical endpoint address.
156
scache_save_endp(smtp_scache, var_smtp_cache_conn, STR(state->endp_label),
157
STR(state->endp_prop), fd);
160
/* smtp_reuse_common - common session reuse code */
162
static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd,
165
const char *myname = "smtp_reuse_common";
166
SMTP_SESSION *session;
169
* Re-activate the SMTP_SESSION object.
171
session = smtp_session_activate(fd, state->dest_prop, state->endp_prop);
173
msg_warn("%s: bad cached session attribute for %s", myname, label);
177
state->session = session;
180
* Send an RSET probe to verify that the session is still good.
182
if (smtp_rset(state) < 0
183
|| (session->features & SMTP_FEATURE_RSET_REJECTED) != 0) {
184
smtp_session_free(session);
185
return (state->session = 0);
189
* Update the list of used cached addresses.
191
htable_enter(state->cache_used, session->addr, (char *) 0);
196
/* smtp_reuse_domain - reuse session cached under domain name */
198
SMTP_SESSION *smtp_reuse_domain(SMTP_STATE *state, int lookup_mx,
199
const char *domain, unsigned port)
201
SMTP_SESSION *session;
205
* Look up the session by its logical name.
207
* Note: if the label needs to be made more specific (with e.g., SASL login
208
* information), just append the text with vstring_sprintf_append().
210
vstring_sprintf(state->dest_label, SMTP_SCACHE_LABEL(lookup_mx),
211
state->service, domain, ntohs(port));
212
if ((fd = scache_find_dest(smtp_scache, STR(state->dest_label),
213
state->dest_prop, state->endp_prop)) < 0)
217
* Re-activate the SMTP_SESSION object, and verify that the session is
220
session = smtp_reuse_common(state, fd, STR(state->dest_label));
224
/* smtp_reuse_addr - reuse session cached under numerical address */
226
SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, DNS_RR *addr, unsigned port)
228
MAI_HOSTADDR_STR hostaddr;
229
SMTP_SESSION *session;
233
* Look up the session by its IP address. This means that we have no
234
* destination-to-address binding properties.
236
* Note: if the label needs to be made more specific (with e.g., SASL login
237
* information), just append the text with vstring_sprintf_append().
239
if (dns_rr_to_pa(addr, &hostaddr) == 0)
241
vstring_sprintf(state->endp_label, SMTP_SCACHE_LABEL(NO_MX_LOOKUP),
242
state->service, hostaddr.buf, ntohs(port));
243
if ((fd = scache_find_endp(smtp_scache, STR(state->endp_label),
244
state->endp_prop)) < 0)
246
VSTRING_RESET(state->dest_prop);
247
VSTRING_TERMINATE(state->dest_prop);
250
* Re-activate the SMTP_SESSION object, and verify that the session is
253
session = smtp_reuse_common(state, fd, STR(state->endp_label));
256
* XXX What if hostnames don't match (addr->name versus session->name),
257
* or if the SASL login name for this host does not match the SASL login
258
* name that was used when opening this session? If something depends
259
* critically on such information being identical, then that information
260
* should be included in the logical and physical labels under which a