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