1 /* $NetBSD: smtp.h,v 1.1.1.2 2010/06/17 18:07:03 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* smtp 3h 6 /* SUMMARY 7 /* smtp client program 8 /* SYNOPSIS 9 /* #include "smtp.h" 10 /* DESCRIPTION 11 /* .nf 12 13 /* 14 * System library. 15 */ 16 #include <string.h> 17 18 /* 19 * Utility library. 20 */ 21 #include <vstream.h> 22 #include <vstring.h> 23 #include <argv.h> 24 #include <htable.h> 25 #include <dict.h> 26 27 /* 28 * Global library. 29 */ 30 #include <deliver_request.h> 31 #include <scache.h> 32 #include <string_list.h> 33 #include <maps.h> 34 #include <tok822.h> 35 #include <dsn_buf.h> 36 #include <header_body_checks.h> 37 38 /* 39 * Postfix TLS library. 40 */ 41 #include <tls.h> 42 43 /* 44 * State information associated with each SMTP delivery request. 45 * Session-specific state is stored separately. 46 */ 47 typedef struct SMTP_STATE { 48 int misc_flags; /* processing flags, see below */ 49 VSTREAM *src; /* queue file stream */ 50 const char *service; /* transport name */ 51 DELIVER_REQUEST *request; /* envelope info, offsets */ 52 struct SMTP_SESSION *session; /* network connection */ 53 int status; /* delivery status */ 54 ssize_t space_left; /* output length control */ 55 56 /* 57 * Connection cache support. The (nexthop_lookup_mx, nexthop_domain, 58 * nexthop_port) triple is a parsed next-hop specification, and should be 59 * a data type by itself. The (service, nexthop_mumble) members specify 60 * the name under which the first good connection should be cached. The 61 * nexthop_mumble members are initialized by the connection management 62 * module. nexthop_domain is reset to null after one connection is saved 63 * under the (service, nexthop_mumble) label, or upon exit from the 64 * connection management module. 65 */ 66 HTABLE *cache_used; /* cached addresses that were used */ 67 VSTRING *dest_label; /* cached logical/physical binding */ 68 VSTRING *dest_prop; /* binding properties, passivated */ 69 VSTRING *endp_label; /* cached session physical endpoint */ 70 VSTRING *endp_prop; /* endpoint properties, passivated */ 71 int nexthop_lookup_mx; /* do/don't MX expand nexthop_domain */ 72 char *nexthop_domain; /* next-hop name or bare address */ 73 unsigned nexthop_port; /* next-hop TCP port, network order */ 74 75 /* 76 * Flags and counters to control the handling of mail delivery errors. 77 * There is some redundancy for sanity checking. At the end of an SMTP 78 * session all recipients should be marked one way or the other. 79 */ 80 int rcpt_left; /* recipients left over */ 81 int rcpt_drop; /* recipients marked as drop */ 82 int rcpt_keep; /* recipients marked as keep */ 83 84 /* 85 * DSN Support introduced major bloat in error processing. 86 */ 87 DSN_BUF *why; /* on-the-fly formatting buffer */ 88 } SMTP_STATE; 89 90 #define SET_NEXTHOP_STATE(state, lookup_mx, domain, port) { \ 91 (state)->nexthop_lookup_mx = lookup_mx; \ 92 (state)->nexthop_domain = mystrdup(domain); \ 93 (state)->nexthop_port = port; \ 94 } 95 96 #define FREE_NEXTHOP_STATE(state) { \ 97 myfree((state)->nexthop_domain); \ 98 (state)->nexthop_domain = 0; \ 99 } 100 101 #define HAVE_NEXTHOP_STATE(state) ((state)->nexthop_domain != 0) 102 103 104 /* 105 * Server features. 106 */ 107 #define SMTP_FEATURE_ESMTP (1<<0) 108 #define SMTP_FEATURE_8BITMIME (1<<1) 109 #define SMTP_FEATURE_PIPELINING (1<<2) 110 #define SMTP_FEATURE_SIZE (1<<3) 111 #define SMTP_FEATURE_STARTTLS (1<<4) 112 #define SMTP_FEATURE_AUTH (1<<5) 113 #define SMTP_FEATURE_XFORWARD_NAME (1<<7) 114 #define SMTP_FEATURE_XFORWARD_ADDR (1<<8) 115 #define SMTP_FEATURE_XFORWARD_PROTO (1<<9) 116 #define SMTP_FEATURE_XFORWARD_HELO (1<<10) 117 #define SMTP_FEATURE_XFORWARD_DOMAIN (1<<11) 118 #define SMTP_FEATURE_BEST_MX (1<<12) /* for next-hop or fall-back */ 119 #define SMTP_FEATURE_RSET_REJECTED (1<<13) /* RSET probe rejected */ 120 #define SMTP_FEATURE_FROM_CACHE (1<<14) /* cached connection */ 121 #define SMTP_FEATURE_DSN (1<<15) /* DSN supported */ 122 #define SMTP_FEATURE_PIX_NO_ESMTP (1<<16) /* PIX smtp fixup mode */ 123 #define SMTP_FEATURE_PIX_DELAY_DOTCRLF (1<<17) /* PIX smtp fixup mode */ 124 #define SMTP_FEATURE_XFORWARD_PORT (1<<18) 125 #define SMTP_FEATURE_EARLY_TLS_MAIL_REPLY (1<<19) /* CVE-2009-3555 */ 126 127 /* 128 * Features that passivate under the endpoint. 129 */ 130 #define SMTP_FEATURE_ENDPOINT_MASK \ 131 (~(SMTP_FEATURE_BEST_MX | SMTP_FEATURE_RSET_REJECTED \ 132 | SMTP_FEATURE_FROM_CACHE)) 133 134 /* 135 * Features that passivate under the logical destination. 136 */ 137 #define SMTP_FEATURE_DESTINATION_MASK (SMTP_FEATURE_BEST_MX) 138 139 /* 140 * Misc flags. 141 */ 142 #define SMTP_MISC_FLAG_LOOP_DETECT (1<<0) 143 #define SMTP_MISC_FLAG_IN_STARTTLS (1<<1) 144 #define SMTP_MISC_FLAG_USE_LMTP (1<<2) 145 #define SMTP_MISC_FLAG_FIRST_NEXTHOP (1<<3) 146 #define SMTP_MISC_FLAG_FINAL_NEXTHOP (1<<4) 147 #define SMTP_MISC_FLAG_FINAL_SERVER (1<<5) 148 #define SMTP_MISC_FLAG_CONN_LOAD (1<<6) 149 #define SMTP_MISC_FLAG_CONN_STORE (1<<7) 150 #define SMTP_MISC_FLAG_COMPLETE_SESSION (1<<8) 151 152 #define SMTP_MISC_FLAG_CONN_CACHE_MASK \ 153 (SMTP_MISC_FLAG_CONN_LOAD | SMTP_MISC_FLAG_CONN_STORE) 154 155 /* 156 * smtp.c 157 */ 158 #define SMTP_HAS_DSN(why) (STR((why)->status)[0] != 0) 159 #define SMTP_HAS_SOFT_DSN(why) (STR((why)->status)[0] == '4') 160 #define SMTP_HAS_HARD_DSN(why) (STR((why)->status)[0] == '5') 161 #define SMTP_HAS_LOOP_DSN(why) \ 162 (SMTP_HAS_DSN(why) && strcmp(STR((why)->status) + 1, ".4.6") == 0) 163 164 #define SMTP_SET_SOFT_DSN(why) (STR((why)->status)[0] = '4') 165 #define SMTP_SET_HARD_DSN(why) (STR((why)->status)[0] = '5') 166 167 extern int smtp_host_lookup_mask; /* host lookup methods to use */ 168 169 #define SMTP_HOST_FLAG_DNS (1<<0) 170 #define SMTP_HOST_FLAG_NATIVE (1<<1) 171 172 extern SCACHE *smtp_scache; /* connection cache instance */ 173 extern STRING_LIST *smtp_cache_dest; /* cached destinations */ 174 175 extern MAPS *smtp_ehlo_dis_maps; /* ehlo keyword filter */ 176 177 extern MAPS *smtp_pix_bug_maps; /* PIX workarounds */ 178 179 extern MAPS *smtp_generic_maps; /* make internal address valid */ 180 extern int smtp_ext_prop_mask; /* address externsion propagation */ 181 182 #ifdef USE_TLS 183 184 extern TLS_APPL_STATE *smtp_tls_ctx; /* client-side TLS engine */ 185 186 #endif 187 188 extern HBC_CHECKS *smtp_header_checks; /* limited header checks */ 189 extern HBC_CHECKS *smtp_body_checks; /* limited body checks */ 190 191 /* 192 * smtp_session.c 193 */ 194 typedef struct SMTP_SESSION { 195 VSTREAM *stream; /* network connection */ 196 char *dest; /* nexthop or fallback */ 197 char *host; /* mail exchanger */ 198 char *addr; /* mail exchanger */ 199 char *namaddr; /* mail exchanger */ 200 char *helo; /* helo response */ 201 unsigned port; /* network byte order */ 202 char *namaddrport; /* mail exchanger, incl. port */ 203 204 VSTRING *buffer; /* I/O buffer */ 205 VSTRING *scratch; /* scratch buffer */ 206 VSTRING *scratch2; /* scratch buffer */ 207 208 int features; /* server features */ 209 off_t size_limit; /* server limit or unknown */ 210 211 ARGV *history; /* transaction log */ 212 int error_mask; /* error classes */ 213 struct MIME_STATE *mime_state; /* mime state machine */ 214 215 int send_proto_helo; /* XFORWARD support */ 216 217 time_t expire_time; /* session reuse expiration time */ 218 int reuse_count; /* # of times reused (for logging) */ 219 int dead; /* No further I/O allowed */ 220 221 #ifdef USE_SASL_AUTH 222 char *sasl_mechanism_list; /* server mechanism list */ 223 char *sasl_username; /* client username */ 224 char *sasl_passwd; /* client password */ 225 struct XSASL_CLIENT *sasl_client; /* SASL internal state */ 226 VSTRING *sasl_reply; /* client response */ 227 #endif 228 229 /* 230 * TLS related state, don't forget to initialize in session_tls_init()! 231 */ 232 #ifdef USE_TLS 233 TLS_SESS_STATE *tls_context; /* TLS session state */ 234 char *tls_nexthop; /* Nexthop domain for cert checks */ 235 int tls_level; /* TLS enforcement level */ 236 int tls_retry_plain; /* Try plain when TLS handshake fails */ 237 char *tls_protocols; /* Acceptable SSL protocols */ 238 char *tls_grade; /* Cipher grade: "export", ... */ 239 VSTRING *tls_exclusions; /* Excluded SSL ciphers */ 240 ARGV *tls_matchargv; /* Cert match patterns */ 241 #endif 242 243 SMTP_STATE *state; /* back link */ 244 } SMTP_SESSION; 245 246 extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, const char *, const char *, 247 const char *, unsigned, time_t, int); 248 extern void smtp_session_free(SMTP_SESSION *); 249 extern int smtp_session_passivate(SMTP_SESSION *, VSTRING *, VSTRING *); 250 extern SMTP_SESSION *smtp_session_activate(int, VSTRING *, VSTRING *); 251 252 #ifdef USE_TLS 253 extern void smtp_tls_list_init(void); 254 255 #endif 256 257 /* 258 * What's in a name? 259 */ 260 #define SMTP_HNAME(rr) (var_smtp_cname_overr ? (rr)->rname : (rr)->qname) 261 262 /* 263 * smtp_connect.c 264 */ 265 extern int smtp_connect(SMTP_STATE *); 266 267 /* 268 * smtp_proto.c 269 */ 270 extern int smtp_helo(SMTP_STATE *); 271 extern int smtp_xfer(SMTP_STATE *); 272 extern int smtp_rset(SMTP_STATE *); 273 extern int smtp_quit(SMTP_STATE *); 274 275 extern HBC_CALL_BACKS smtp_hbc_callbacks[]; 276 277 /* 278 * A connection is re-usable if session->expire_time is > 0 and the 279 * expiration time has not been reached. This is subtle because the timer 280 * can expire between sending a command and receiving the reply for that 281 * command. 282 * 283 * But wait, there is more! When SMTP command pipelining is enabled, there are 284 * two protocol loops that execute at very different times: one loop that 285 * generates commands, and one loop that receives replies to those commands. 286 * These will be called "sender loop" and "receiver loop", respectively. At 287 * well-defined protocol synchronization points, the sender loop pauses to 288 * let the receiver loop catch up. 289 * 290 * When we choose to reuse a connection, both the sender and receiver protocol 291 * loops end with "." (mail delivery) or "RSET" (address probe). When we 292 * choose not to reuse, both the sender and receiver protocol loops end with 293 * "QUIT". The problem is that we must make the same protocol choices in 294 * both the sender and receiver loops, even though those loops may execute 295 * at completely different times. 296 * 297 * We "freeze" the choice in the sender loop, just before we generate "." or 298 * "RSET". The reader loop leaves the connection cachable even if the timer 299 * expires by the time the response arrives. The connection cleanup code 300 * will call smtp_quit() for connections with an expired cache expiration 301 * timer. 302 * 303 * We could have made the programmer's life a lot simpler by not making a 304 * choice at all, and always leaving it up to the connection cleanup code to 305 * call smtp_quit() for connections with an expired cache expiration timer. 306 * 307 * As a general principle, neither the sender loop nor the receiver loop must 308 * modify the connection caching state, if that can affect the receiver 309 * state machine for not-yet processed replies to already-generated 310 * commands. This restriction does not apply when we have to exit the 311 * protocol loops prematurely due to e.g., timeout or connection loss, so 312 * that those pending replies will never be received. 313 * 314 * But wait, there is even more! Only the first good connection for a specific 315 * destination may be cached under both the next-hop destination name and 316 * the server address; connections to alternate servers must be cached under 317 * the server address alone. This means we must distinguish between bad 318 * connections and other reasons why connections cannot be cached. 319 */ 320 #define THIS_SESSION_IS_CACHED \ 321 (!THIS_SESSION_IS_DEAD && session->expire_time > 0) 322 323 #define THIS_SESSION_IS_EXPIRED \ 324 (THIS_SESSION_IS_CACHED \ 325 && session->expire_time < vstream_ftime(session->stream)) 326 327 #define THIS_SESSION_IS_BAD \ 328 (!THIS_SESSION_IS_DEAD && session->expire_time < 0) 329 330 #define THIS_SESSION_IS_DEAD \ 331 (session->dead != 0) 332 333 /* Bring the bad news. */ 334 335 #define DONT_CACHE_THIS_SESSION \ 336 (session->expire_time = 0) 337 338 #define DONT_CACHE_BAD_SESSION \ 339 (session->expire_time = -1) 340 341 #define DONT_USE_DEAD_SESSION \ 342 (session->dead = 1) 343 344 /* Initialization. */ 345 346 #define USE_NEWBORN_SESSION \ 347 (session->dead = 0) 348 349 #define CACHE_THIS_SESSION_UNTIL(when) \ 350 (session->expire_time = (when)) 351 352 /* 353 * Encapsulate the following so that we don't expose details of of 354 * connection management and error handling to the SMTP protocol engine. 355 */ 356 #define RETRY_AS_PLAINTEXT do { \ 357 session->tls_retry_plain = 1; \ 358 state->misc_flags &= ~SMTP_MISC_FLAG_FINAL_SERVER; \ 359 } while (0) 360 361 /* 362 * smtp_chat.c 363 */ 364 typedef struct SMTP_RESP { /* server response */ 365 int code; /* SMTP code */ 366 const char *dsn; /* enhanced status */ 367 char *str; /* full reply */ 368 VSTRING *dsn_buf; /* status buffer */ 369 VSTRING *str_buf; /* reply buffer */ 370 } SMTP_RESP; 371 372 extern void PRINTFLIKE(2, 3) smtp_chat_cmd(SMTP_SESSION *, const char *,...); 373 extern DICT *smtp_chat_resp_filter; 374 extern SMTP_RESP *smtp_chat_resp(SMTP_SESSION *); 375 extern void smtp_chat_init(SMTP_SESSION *); 376 extern void smtp_chat_reset(SMTP_SESSION *); 377 extern void smtp_chat_notify(SMTP_SESSION *); 378 379 #define SMTP_RESP_FAKE(resp, _dsn) \ 380 ((resp)->code = 0, \ 381 (resp)->dsn = (_dsn), \ 382 (resp)->str = DSN_BY_LOCAL_MTA, \ 383 (resp)) 384 385 #define DSN_BY_LOCAL_MTA ((char *) 0) /* DSN issued by local MTA */ 386 387 /* 388 * These operations implement a redundant mark-and-sweep algorithm that 389 * explicitly accounts for the fate of every recipient. The interface is 390 * documented in smtp_rcpt.c, which also implements the sweeping. The 391 * smtp_trouble.c module does most of the marking after failure. 392 * 393 * When a delivery fails or succeeds, take one of the following actions: 394 * 395 * - Mark the recipient as KEEP (deliver to alternate MTA) and do not update 396 * the delivery request status. 397 * 398 * - Mark the recipient as DROP (remove from delivery request), log whether 399 * delivery succeeded or failed, delete the recipient from the queue file 400 * and/or update defer or bounce logfiles, and update the delivery request 401 * status. 402 * 403 * At the end of a delivery attempt, all recipients must be marked one way or 404 * the other. Failure to do so will trigger a panic. 405 */ 406 #define SMTP_RCPT_STATE_KEEP 1 /* send to backup host */ 407 #define SMTP_RCPT_STATE_DROP 2 /* remove from request */ 408 #define SMTP_RCPT_INIT(state) do { \ 409 (state)->rcpt_drop = (state)->rcpt_keep = 0; \ 410 (state)->rcpt_left = state->request->rcpt_list.len; \ 411 } while (0) 412 413 #define SMTP_RCPT_DROP(state, rcpt) do { \ 414 (rcpt)->u.status = SMTP_RCPT_STATE_DROP; (state)->rcpt_drop++; \ 415 } while (0) 416 417 #define SMTP_RCPT_KEEP(state, rcpt) do { \ 418 (rcpt)->u.status = SMTP_RCPT_STATE_KEEP; (state)->rcpt_keep++; \ 419 } while (0) 420 421 #define SMTP_RCPT_ISMARKED(rcpt) ((rcpt)->u.status != 0) 422 423 #define SMTP_RCPT_LEFT(state) (state)->rcpt_left 424 425 extern void smtp_rcpt_cleanup(SMTP_STATE *); 426 extern void smtp_rcpt_done(SMTP_STATE *, SMTP_RESP *, RECIPIENT *); 427 428 /* 429 * smtp_trouble.c 430 */ 431 extern int smtp_sess_fail(SMTP_STATE *); 432 extern int PRINTFLIKE(4, 5) smtp_site_fail(SMTP_STATE *, const char *, 433 SMTP_RESP *, const char *,...); 434 extern int PRINTFLIKE(4, 5) smtp_mesg_fail(SMTP_STATE *, const char *, 435 SMTP_RESP *, const char *,...); 436 extern void PRINTFLIKE(5, 6) smtp_rcpt_fail(SMTP_STATE *, RECIPIENT *, 437 const char *, SMTP_RESP *, 438 const char *,...); 439 extern int smtp_stream_except(SMTP_STATE *, int, const char *); 440 441 /* 442 * smtp_unalias.c 443 */ 444 extern const char *smtp_unalias_name(const char *); 445 extern VSTRING *smtp_unalias_addr(VSTRING *, const char *); 446 447 /* 448 * smtp_state.c 449 */ 450 extern SMTP_STATE *smtp_state_alloc(void); 451 extern void smtp_state_free(SMTP_STATE *); 452 453 /* 454 * smtp_map11.c 455 */ 456 extern int smtp_map11_external(VSTRING *, MAPS *, int); 457 extern int smtp_map11_tree(TOK822 *, MAPS *, int); 458 extern int smtp_map11_internal(VSTRING *, MAPS *, int); 459 460 /* 461 * Silly little macros. 462 */ 463 #define STR(s) vstring_str(s) 464 #define LEN(s) VSTRING_LEN(s) 465 466 /* LICENSE 467 /* .ad 468 /* .fi 469 /* The Secure Mailer license must be distributed with this software. 470 /* AUTHOR(S) 471 /* Wietse Venema 472 /* IBM T.J. Watson Research 473 /* P.O. Box 704 474 /* Yorktown Heights, NY 10598, USA 475 /* 476 /* TLS support originally by: 477 /* Lutz Jaenicke 478 /* BTU Cottbus 479 /* Allgemeine Elektrotechnik 480 /* Universitaetsplatz 3-4 481 /* D-03044 Cottbus, Germany 482 /*--*/ 483