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