xref: /netbsd-src/external/ibm-public/postfix/dist/src/smtp/smtp_reuse.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /*	$NetBSD: smtp_reuse.c,v 1.1.1.4 2014/07/06 19:27:56 tron Exp $	*/
2 
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>
11 /*
12 /*	void	smtp_save_session(state, name_key_flags, endp_key_flags)
13 /*	SMTP_STATE *state;
14 /*	int	name_key_flags;
15 /*	int	endp_key_flags;
16 /*
17 /*	SMTP_SESSION *smtp_reuse_nexthop(state, name_key_flags)
18 /*	SMTP_STATE *state;
19 /*	int	name_key_flags;
20 /*
21 /*	SMTP_SESSION *smtp_reuse_addr(state, endp_key_flags)
22 /*	SMTP_STATE *state;
23 /*	int	endp_key_flags;
24 /* DESCRIPTION
25 /*	This module implements the SMTP client specific interface to
26 /*	the generic session cache infrastructure.
27 /*
28 /*	A cached connection is closed when the TLS policy requires
29 /*	that TLS is enabled.
30 /*
31 /*	smtp_save_session() stores the current session under the
32 /*	next-hop logical destination (if available) and under the
33 /*	remote server address.  The SMTP_SESSION object is destroyed.
34 /*
35 /*	smtp_reuse_nexthop() looks up a cached session by its logical
36 /*	destination, and verifies that the session is still alive.
37 /*	The restored session information includes the "best MX" bit
38 /*	and overrides the iterator dest, host and addr fields.
39 /*	The result is null in case of failure.
40 /*
41 /*	smtp_reuse_addr() looks up a cached session by its server
42 /*	address, and verifies that the session is still alive.
43 /*	The restored session information does not include the "best
44 /*	MX" bit, and does not override the iterator dest, host and
45 /*	addr fields.
46 /*	The result is null in case of failure.
47 /*
48 /*	Arguments:
49 /* .IP state
50 /*	SMTP client state, including the current session, the original
51 /*	next-hop domain, etc.
52 /* .IP name_key_flags
53 /*	Explicit declaration of context that should be used to look
54 /*	up a cached connection by its logical destination.
55 /*	See smtp_key(3) for details.
56 /* .IP endp_key_flags
57 /*	Explicit declaration of context that should be used to look
58 /*	up a cached connection by its server address.
59 /*	See smtp_key(3) for details.
60 /* LICENSE
61 /* .ad
62 /* .fi
63 /*	The Secure Mailer license must be distributed with this software.
64 /* AUTHOR(S)
65 /*	Wietse Venema
66 /*	IBM T.J. Watson Research
67 /*	P.O. Box 704
68 /*	Yorktown Heights, NY 10598, USA
69 /*--*/
70 
71 /* System library. */
72 
73 #include <sys_defs.h>
74 #include <sys/socket.h>
75 #include <netinet/in.h>
76 #include <arpa/inet.h>
77 #include <unistd.h>
78 #include <string.h>
79 
80 /* Utility library. */
81 
82 #include <msg.h>
83 #include <mymalloc.h>
84 #include <vstream.h>
85 #include <vstring.h>
86 #include <htable.h>
87 #include <stringops.h>
88 
89 /* Global library. */
90 
91 #include <scache.h>
92 #include <mail_params.h>
93 
94 /* Application-specific. */
95 
96 #include <smtp.h>
97 #include <smtp_reuse.h>
98 
99  /*
100   * Key field delimiter, and place holder field value for
101   * unavailable/inapplicable information.
102   */
103 #define SMTP_REUSE_KEY_DELIM_NA	"\n*"
104 
105 /* smtp_save_session - save session under next-hop name and server address */
106 
107 void    smtp_save_session(SMTP_STATE *state, int name_key_flags,
108 			          int endp_key_flags)
109 {
110     SMTP_SESSION *session = state->session;
111     int     fd;
112 
113     /*
114      * Encode the next-hop logical destination, if available. Reuse storage
115      * that is also used for cache lookup queries.
116      */
117     if (HAVE_NEXTHOP_STATE(state))
118 	smtp_key_prefix(state->dest_label, SMTP_REUSE_KEY_DELIM_NA,
119 			state->iterator, name_key_flags);
120 
121     /*
122      * Encode the physical endpoint name. Reuse storage that is also used for
123      * cache lookup queries.
124      */
125     smtp_key_prefix(state->endp_label, SMTP_REUSE_KEY_DELIM_NA,
126 		    state->iterator, endp_key_flags);
127 
128     /*
129      * Passivate the SMTP_SESSION object, destroying the object in the
130      * process. Reuse storage that is also used for cache lookup results.
131      */
132     fd = smtp_session_passivate(session, state->dest_prop, state->endp_prop);
133     state->session = 0;
134 
135     /*
136      * Save the session under the next-hop name, if available.
137      *
138      * XXX The logical to physical binding can be kept for as long as the DNS
139      * allows us to (but that could result in the caching of lots of unused
140      * bindings). The session should be idle for no more than 30 seconds or
141      * so.
142      */
143     if (HAVE_NEXTHOP_STATE(state))
144 	scache_save_dest(smtp_scache, var_smtp_cache_conn, STR(state->dest_label),
145 			 STR(state->dest_prop), STR(state->endp_label));
146 
147     /*
148      * Save every good session under its physical endpoint address.
149      */
150     scache_save_endp(smtp_scache, var_smtp_cache_conn, STR(state->endp_label),
151 		     STR(state->endp_prop), fd);
152 }
153 
154 /* smtp_reuse_common - common session reuse code */
155 
156 static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd,
157 				               const char *label)
158 {
159     const char *myname = "smtp_reuse_common";
160     SMTP_ITERATOR *iter = state->iterator;
161     SMTP_SESSION *session;
162 
163     /*
164      * Can't happen. Both smtp_reuse_nexthop() and smtp_reuse_addr() decline
165      * the request when the TLS policy is not TLS_LEV_NONE.
166      */
167 #ifdef USE_TLS
168     if (state->tls->level > TLS_LEV_NONE)
169 	msg_panic("%s: unexpected plain-text cached session to %s",
170 		  myname, label);
171 #endif
172 
173     /*
174      * Re-activate the SMTP_SESSION object.
175      */
176     session = smtp_session_activate(fd, state->iterator, state->dest_prop,
177 				    state->endp_prop);
178     if (session == 0) {
179 	msg_warn("%s: bad cached session attribute for %s", myname, label);
180 	(void) close(fd);
181 	return (0);
182     }
183     state->session = session;
184     session->state = state;
185 #ifdef USE_TLS
186     session->tls = state->tls;			/* TEMPORARY */
187 #endif
188 
189     /*
190      * Send an RSET probe to verify that the session is still good.
191      */
192     if (smtp_rset(state) < 0
193 	|| (session->features & SMTP_FEATURE_RSET_REJECTED) != 0) {
194 	smtp_session_free(session);
195 	return (state->session = 0);
196     }
197 
198     /*
199      * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE.
200      */
201     vstream_tweak_sock(session->stream);
202 
203     /*
204      * Update the list of used cached addresses.
205      */
206     htable_enter(state->cache_used, STR(iter->addr), (char *) 0);
207 
208     return (session);
209 }
210 
211 /* smtp_reuse_nexthop - reuse session cached under nexthop name */
212 
213 SMTP_SESSION *smtp_reuse_nexthop(SMTP_STATE *state, int name_key_flags)
214 {
215     SMTP_SESSION *session;
216     int     fd;
217 
218     /*
219      * Don't look up an existing plaintext connection when a new connection
220      * would (try to) use TLS.
221      */
222 #ifdef USE_TLS
223     if (state->tls->level > TLS_LEV_NONE)
224 	return (0);
225 #endif
226 
227     /*
228      * Look up the session by its logical name.
229      */
230     smtp_key_prefix(state->dest_label, SMTP_REUSE_KEY_DELIM_NA,
231 		    state->iterator, name_key_flags);
232     if ((fd = scache_find_dest(smtp_scache, STR(state->dest_label),
233 			       state->dest_prop, state->endp_prop)) < 0)
234 	return (0);
235 
236     /*
237      * Re-activate the SMTP_SESSION object, and verify that the session is
238      * still good.
239      */
240     session = smtp_reuse_common(state, fd, STR(state->dest_label));
241     return (session);
242 }
243 
244 /* smtp_reuse_addr - reuse session cached under numerical address */
245 
246 SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, int endp_key_flags)
247 {
248     SMTP_SESSION *session;
249     int     fd;
250 
251     /*
252      * Don't look up an existing plaintext connection when a new connection
253      * would (try to) use TLS.
254      */
255 #ifdef USE_TLS
256     if (state->tls->level > TLS_LEV_NONE)
257 	return (0);
258 #endif
259 
260     /*
261      * Look up the session by its IP address. This means that we have no
262      * destination-to-address binding properties.
263      */
264     smtp_key_prefix(state->endp_label, SMTP_REUSE_KEY_DELIM_NA,
265 		    state->iterator, endp_key_flags);
266     if ((fd = scache_find_endp(smtp_scache, STR(state->endp_label),
267 			       state->endp_prop)) < 0)
268 	return (0);
269     VSTRING_RESET(state->dest_prop);
270     VSTRING_TERMINATE(state->dest_prop);
271 
272     /*
273      * Re-activate the SMTP_SESSION object, and verify that the session is
274      * still good.
275      */
276     session = smtp_reuse_common(state, fd, STR(state->endp_label));
277 
278     return (session);
279 }
280