xref: /netbsd-src/external/ibm-public/postfix/dist/src/smtp/smtp_reuse.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: smtp_reuse.c,v 1.2 2017/02/14 01:16:48 christos 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 
186     /*
187      * Send an RSET probe to verify that the session is still good.
188      */
189     if (smtp_rset(state) < 0
190 	|| (session->features & SMTP_FEATURE_RSET_REJECTED) != 0) {
191 	smtp_session_free(session);
192 	return (state->session = 0);
193     }
194 
195     /*
196      * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE.
197      */
198     vstream_tweak_sock(session->stream);
199 
200     /*
201      * Update the list of used cached addresses.
202      */
203     htable_enter(state->cache_used, STR(iter->addr), (void *) 0);
204 
205     return (session);
206 }
207 
208 /* smtp_reuse_nexthop - reuse session cached under nexthop name */
209 
210 SMTP_SESSION *smtp_reuse_nexthop(SMTP_STATE *state, int name_key_flags)
211 {
212     SMTP_SESSION *session;
213     int     fd;
214 
215     /*
216      * Don't look up an existing plaintext connection when a new connection
217      * would (try to) use TLS.
218      */
219 #ifdef USE_TLS
220     if (state->tls->level > TLS_LEV_NONE)
221 	return (0);
222 #endif
223 
224     /*
225      * Look up the session by its logical name.
226      */
227     smtp_key_prefix(state->dest_label, SMTP_REUSE_KEY_DELIM_NA,
228 		    state->iterator, name_key_flags);
229     if ((fd = scache_find_dest(smtp_scache, STR(state->dest_label),
230 			       state->dest_prop, state->endp_prop)) < 0)
231 	return (0);
232 
233     /*
234      * Re-activate the SMTP_SESSION object, and verify that the session is
235      * still good.
236      */
237     session = smtp_reuse_common(state, fd, STR(state->dest_label));
238     return (session);
239 }
240 
241 /* smtp_reuse_addr - reuse session cached under numerical address */
242 
243 SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, int endp_key_flags)
244 {
245     SMTP_SESSION *session;
246     int     fd;
247 
248     /*
249      * Don't look up an existing plaintext connection when a new connection
250      * would (try to) use TLS.
251      */
252 #ifdef USE_TLS
253     if (state->tls->level > TLS_LEV_NONE)
254 	return (0);
255 #endif
256 
257     /*
258      * Look up the session by its IP address. This means that we have no
259      * destination-to-address binding properties.
260      */
261     smtp_key_prefix(state->endp_label, SMTP_REUSE_KEY_DELIM_NA,
262 		    state->iterator, endp_key_flags);
263     if ((fd = scache_find_endp(smtp_scache, STR(state->endp_label),
264 			       state->endp_prop)) < 0)
265 	return (0);
266     VSTRING_RESET(state->dest_prop);
267     VSTRING_TERMINATE(state->dest_prop);
268 
269     /*
270      * Re-activate the SMTP_SESSION object, and verify that the session is
271      * still good.
272      */
273     session = smtp_reuse_common(state, fd, STR(state->endp_label));
274 
275     return (session);
276 }
277