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