Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / smtp / smtp_reuse.c
blobf24e269f27f8c8a5edaece3d20baad98a635d93a
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* smtp_reuse 3
6 /* SUMMARY
7 /* SMTP session cache glue
8 /* SYNOPSIS
9 /* #include <smtp.h>
10 /* #include <smtp_reuse.h>
12 /* void smtp_save_session(state)
13 /* SMTP_STATE *state;
15 /* SMTP_SESSION *smtp_reuse_domain(state, lookup_mx, domain, port)
16 /* SMTP_STATE *state;
17 /* int lookup_mx;
18 /* char *domain;
19 /* unsigned port;
21 /* SMTP_SESSION *smtp_reuse_addr(state, addr, port)
22 /* SMTP_STATE *state;
23 /* const char *addr;
24 /* unsigned port;
25 /* DESCRIPTION
26 /* This module implements the SMTP client specific interface to
27 /* the generic session cache infrastructure.
29 /* smtp_save_session() stores the current session under the
30 /* next-hop logical destination (if available) and under the
31 /* remote server address. The SMTP_SESSION object is destroyed.
33 /* smtp_reuse_domain() looks up a cached session by its logical
34 /* destination, and verifies that the session is still alive.
35 /* The restored session information includes the "best MX" bit.
36 /* The result is null in case of failure.
38 /* smtp_reuse_addr() looks up a cached session by its server
39 /* address, and verifies that the session is still alive.
40 /* This operation is disabled when the legacy tls_per_site
41 /* or smtp_sasl_password_maps features are enabled.
42 /* The result is null in case of failure.
44 /* Arguments:
45 /* .IP state
46 /* SMTP client state, including the current session, the original
47 /* next-hop domain, etc.
48 /* .IP lookup_mx
49 /* Whether or not the domain is subject to MX lookup.
50 /* .IP domain
51 /* Domain name or bare numerical address.
52 /* .IP addr
53 /* The remote server address as printable text.
54 /* .IP port
55 /* The remote server port, network byte order.
56 /* LICENSE
57 /* .ad
58 /* .fi
59 /* The Secure Mailer license must be distributed with this software.
60 /* AUTHOR(S)
61 /* Wietse Venema
62 /* IBM T.J. Watson Research
63 /* P.O. Box 704
64 /* Yorktown Heights, NY 10598, USA
65 /*--*/
67 /* System library. */
69 #include <sys_defs.h>
70 #include <sys/socket.h>
71 #include <netinet/in.h>
72 #include <arpa/inet.h>
73 #include <unistd.h>
74 #include <string.h>
76 /* Utility library. */
78 #include <msg.h>
79 #include <mymalloc.h>
80 #include <vstream.h>
81 #include <vstring.h>
82 #include <htable.h>
83 #include <stringops.h>
85 /* Global library. */
87 #include <scache.h>
88 #include <mail_params.h>
90 /* Application-specific. */
92 #include <smtp.h>
93 #include <smtp_reuse.h>
96 * We encode the MX lookup/A lookup method into the name under which SMTP
97 * session information is cached. The following macros serve to make the
98 * remainder of the code less obscure.
100 #define NO_MX_LOOKUP 0
102 #define SMTP_SCACHE_LABEL(mx_lookup_flag) \
103 ((mx_lookup_flag) ? "%s:%s:%u" : "%s:[%s]:%u")
105 /* smtp_save_session - save session under next-hop name and server address */
107 void smtp_save_session(SMTP_STATE *state)
109 SMTP_SESSION *session = state->session;
110 int fd;
113 * Encode the next-hop logical destination, if available. Reuse storage
114 * that is also used for cache lookup queries.
116 * Note: if the label needs to be made more specific (with e.g., SASL login
117 * information), just append the text with vstring_sprintf_append().
119 if (HAVE_NEXTHOP_STATE(state))
120 vstring_sprintf(state->dest_label,
121 SMTP_SCACHE_LABEL(state->nexthop_lookup_mx),
122 state->service, state->nexthop_domain,
123 ntohs(state->nexthop_port));
126 * Encode the physical endpoint name. Reuse storage that is also used for
127 * cache lookup queries.
129 * Note: if the label needs to be made more specific (with e.g., SASL login
130 * information), just append the text with vstring_sprintf_append().
132 vstring_sprintf(state->endp_label,
133 SMTP_SCACHE_LABEL(NO_MX_LOOKUP),
134 state->service, session->addr, ntohs(session->port));
137 * Passivate the SMTP_SESSION object, destroying the object in the
138 * process. Reuse storage that is also used for cache lookup results.
140 fd = smtp_session_passivate(session, state->dest_prop, state->endp_prop);
141 state->session = 0;
144 * Save the session under the next-hop name, if available.
146 * XXX The logical to physical binding can be kept for as long as the DNS
147 * allows us to (but that could result in the caching of lots of unused
148 * bindings). The session should be idle for no more than 30 seconds or
149 * so.
151 if (HAVE_NEXTHOP_STATE(state))
152 scache_save_dest(smtp_scache, var_smtp_cache_conn, STR(state->dest_label),
153 STR(state->dest_prop), STR(state->endp_label));
156 * Save every good session under its physical endpoint address.
158 scache_save_endp(smtp_scache, var_smtp_cache_conn, STR(state->endp_label),
159 STR(state->endp_prop), fd);
162 /* smtp_reuse_common - common session reuse code */
164 static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd,
165 const char *label)
167 const char *myname = "smtp_reuse_common";
168 SMTP_SESSION *session;
171 * Re-activate the SMTP_SESSION object.
173 session = smtp_session_activate(fd, state->dest_prop, state->endp_prop);
174 if (session == 0) {
175 msg_warn("%s: bad cached session attribute for %s", myname, label);
176 (void) close(fd);
177 return (0);
179 state->session = session;
180 session->state = state;
183 * XXX Temporary fix.
185 * Cached connections are always plaintext. They must never be reused when
186 * TLS encryption is required.
188 * As long as we support the legacy smtp_tls_per_site feature, we must
189 * search the connection cache before making TLS policy decisions. This
190 * is because the policy can depend on the server name. For example, a
191 * site could have a global policy that requires encryption, with
192 * per-server exceptions that allow plaintext.
194 * With the newer smtp_tls_policy_maps feature, the policy depends on the
195 * next-hop destination only. We can avoid unnecessary connection cache
196 * lookups, because we can compute the TLS policy much earlier.
198 #ifdef USE_TLS
199 if (session->tls_level >= TLS_LEV_ENCRYPT) {
200 if (msg_verbose)
201 msg_info("%s: skipping plain-text cached session to %s",
202 myname, label);
203 smtp_quit(state); /* Close politely */
204 smtp_session_free(session); /* And avoid leaks */
205 return (state->session = 0);
207 #endif
210 * Send an RSET probe to verify that the session is still good.
212 if (smtp_rset(state) < 0
213 || (session->features & SMTP_FEATURE_RSET_REJECTED) != 0) {
214 smtp_session_free(session);
215 return (state->session = 0);
219 * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE.
221 vstream_tweak_sock(session->stream);
224 * Update the list of used cached addresses.
226 htable_enter(state->cache_used, session->addr, (char *) 0);
228 return (session);
231 /* smtp_reuse_domain - reuse session cached under domain name */
233 SMTP_SESSION *smtp_reuse_domain(SMTP_STATE *state, int lookup_mx,
234 const char *domain, unsigned port)
236 SMTP_SESSION *session;
237 int fd;
240 * Look up the session by its logical name.
242 * Note: if the label needs to be made more specific (with e.g., SASL login
243 * information), just append the text with vstring_sprintf_append().
245 vstring_sprintf(state->dest_label, SMTP_SCACHE_LABEL(lookup_mx),
246 state->service, domain, ntohs(port));
247 if ((fd = scache_find_dest(smtp_scache, STR(state->dest_label),
248 state->dest_prop, state->endp_prop)) < 0)
249 return (0);
252 * Re-activate the SMTP_SESSION object, and verify that the session is
253 * still good.
255 session = smtp_reuse_common(state, fd, STR(state->dest_label));
256 return (session);
259 /* smtp_reuse_addr - reuse session cached under numerical address */
261 SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, const char *addr,
262 unsigned port)
264 SMTP_SESSION *session;
265 int fd;
268 * XXX Disable connection cache lookup by server IP address when the
269 * tls_per_site policy or smtp_sasl_password_maps features are enabled.
270 * This connection may have been created under a different hostname that
271 * resolves to the same IP address. We don't want to use the wrong SASL
272 * credentials or the wrong TLS policy.
274 if ((var_smtp_tls_per_site && *var_smtp_tls_per_site)
275 || (var_smtp_sasl_passwd && *var_smtp_sasl_passwd))
276 return (0);
279 * Look up the session by its IP address. This means that we have no
280 * destination-to-address binding properties.
282 * Note: if the label needs to be made more specific (with e.g., SASL login
283 * information), just append the text with vstring_sprintf_append().
285 vstring_sprintf(state->endp_label, SMTP_SCACHE_LABEL(NO_MX_LOOKUP),
286 state->service, addr, ntohs(port));
287 if ((fd = scache_find_endp(smtp_scache, STR(state->endp_label),
288 state->endp_prop)) < 0)
289 return (0);
290 VSTRING_RESET(state->dest_prop);
291 VSTRING_TERMINATE(state->dest_prop);
294 * Re-activate the SMTP_SESSION object, and verify that the session is
295 * still good.
297 session = smtp_reuse_common(state, fd, STR(state->endp_label));
300 * XXX What if hostnames don't match (addr->name versus session->name),
301 * or if the SASL login name for this host does not match the SASL login
302 * name that was used when opening this session? If something depends
303 * critically on such information being identical, then that information
304 * should be included in the logical and physical labels under which a
305 * session is cached.
307 return (session);