1 /* $NetBSD: postscreen_smtpd.c,v 1.3 2020/03/18 19:05:19 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* postscreen_smtpd 3 6 /* SUMMARY 7 /* postscreen built-in SMTP server engine 8 /* SYNOPSIS 9 /* #include <postscreen.h> 10 /* 11 /* void psc_smtpd_pre_jail_init(void) 12 /* 13 /* void psc_smtpd_init(void) 14 /* 15 /* void psc_smtpd_tests(state) 16 /* PSC_STATE *state; 17 /* 18 /* void PSC_SMTPD_X21(state, final_reply) 19 /* PSC_STATE *state; 20 /* const char *final_reply; 21 /* DESCRIPTION 22 /* psc_smtpd_pre_jail_init() performs one-time per-process 23 /* initialization during the "before chroot" execution phase. 24 /* 25 /* psc_smtpd_init() performs one-time per-process initialization. 26 /* 27 /* psc_smtpd_tests() starts up an SMTP server engine for deep 28 /* protocol tests and for collecting helo/sender/recipient 29 /* information. 30 /* 31 /* PSC_SMTPD_X21() redirects the SMTP client to an SMTP server 32 /* engine, which sends the specified final reply at the first 33 /* legitimate opportunity without doing any protocol tests. 34 /* 35 /* Unlike the Postfix SMTP server, this engine does not announce 36 /* PIPELINING support. This exposes spambots that pipeline 37 /* their commands anyway. Like the Postfix SMTP server, this 38 /* engine will accept input with bare newline characters. To 39 /* pass the "pipelining" and "bare newline" test, the client 40 /* has to properly speak SMTP all the way to the RCPT TO 41 /* command. These tests fail if the client violates the protocol 42 /* at any stage. 43 /* 44 /* No support is announced for AUTH, XCLIENT or XFORWARD. 45 /* Clients that need this should be whitelisted or should talk 46 /* directly to the submission service. 47 /* 48 /* The engine rejects RCPT TO and VRFY commands with the 49 /* state->rcpt_reply response which depends on program history, 50 /* rejects ETRN with a generic response, and closes the 51 /* connection after QUIT. 52 /* 53 /* Since this engine defers or rejects all non-junk commands, 54 /* there is no point maintaining separate counters for "error" 55 /* commands and "junk" commands. Instead, the engine maintains 56 /* a per-session command counter, and terminates the session 57 /* with a 421 reply when the command count exceeds the limit. 58 /* 59 /* We limit the command count, as well as the total time to 60 /* receive a command. This limits the time per client more 61 /* effectively than would be possible with read() timeouts. 62 /* 63 /* There is no concern about getting blocked on output. The 64 /* psc_send() routine uses non-blocking output, and discards 65 /* output that the client is not willing to receive. 66 /* PROTOCOL INSPECTION VERSUS CONTENT INSPECTION 67 /* The goal of postscreen is to keep spambots away from Postfix. 68 /* To recognize spambots, postscreen measures properties of 69 /* the client IP address and of the client SMTP protocol 70 /* implementation. These client properties don't change with 71 /* each delivery attempt. Therefore it is possible to make a 72 /* long-term decision after a single measurement. For example, 73 /* allow a good client to skip the DNSBL test for 24 hours, 74 /* or to skip the pipelining test for one week. 75 /* 76 /* If postscreen were to measure properties of message content 77 /* (MIME compliance, etc.) then it would measure properties 78 /* that may change with each delivery attempt. Here, it would 79 /* be wrong to make a long-term decision after a single 80 /* measurement. Instead, postscreen would need to develop a 81 /* ranking based on the content of multiple messages from the 82 /* same client. 83 /* 84 /* Many spambots avoid spamming the same site repeatedly. 85 /* Thus, postscreen must make decisions after a single 86 /* measurement. Message content is not a good indicator for 87 /* making long-term decisions after single measurements, and 88 /* that is why postscreen does not inspect message content. 89 /* REJECTING RCPT TO VERSUS SENDING LIVE SOCKETS TO SMTPD(8) 90 /* When post-handshake protocol tests are enabled, postscreen 91 /* rejects the RCPT TO command from a good client, and forces 92 /* it to deliver mail in a later session. This is why 93 /* post-handshake protocol tests have a longer expiration time 94 /* than pre-handshake tests. 95 /* 96 /* Instead, postscreen could send the network socket to smtpd(8) 97 /* and ship the session history (including TLS and other SMTP 98 /* or non-SMTP attributes) as auxiliary data. The Postfix SMTP 99 /* server would then use new code to replay the session history, 100 /* and would use existing code to validate the client, helo, 101 /* sender and recipient address. 102 /* 103 /* Such an approach would increase the implementation and 104 /* maintenance effort, because: 105 /* 106 /* 1) New replay code would be needed in smtpd(8), such that 107 /* the HELO, EHLO, and MAIL command handlers can delay their 108 /* error responses until the RCPT TO reply. 109 /* 110 /* 2) postscreen(8) would have to implement more of smtpd(8)'s 111 /* syntax checks, to avoid confusing delayed "syntax error" 112 /* and other error responses syntax error responses while 113 /* replaying history. 114 /* 115 /* 3) New code would be needed in postscreen(8) and smtpd(8) 116 /* to send and receive the session history (including TLS and 117 /* other SMTP or non-SMTP attributes) as auxiliary data while 118 /* sending the network socket from postscreen(8) to smtpd(8). 119 /* REJECTING RCPT TO VERSUS PROXYING LIVE SESSIONS TO SMTPD(8) 120 /* An alternative would be to proxy the session history to a 121 /* real Postfix SMTP process, presumably passing TLS and other 122 /* attributes via an extended XCLIENT implementation. That 123 /* would require all the work described in 2) above, plus 124 /* duplication of all the features of the smtpd(8) TLS engine, 125 /* plus additional XCLIENT support for a lot more attributes. 126 /* LICENSE 127 /* .ad 128 /* .fi 129 /* The Secure Mailer license must be distributed with this software. 130 /* AUTHOR(S) 131 /* Wietse Venema 132 /* IBM T.J. Watson Research 133 /* P.O. Box 704 134 /* Yorktown Heights, NY 10598, USA 135 /* 136 /* Wietse Venema 137 /* Google, Inc. 138 /* 111 8th Avenue 139 /* New York, NY 10011, USA 140 /*--*/ 141 142 /* System library. */ 143 144 #include <sys_defs.h> 145 #include <string.h> 146 #include <ctype.h> 147 148 #ifdef STRCASECMP_IN_STRINGS_H 149 #include <strings.h> 150 #endif 151 152 /* Utility library. */ 153 154 #include <msg.h> 155 #include <stringops.h> 156 #include <mymalloc.h> 157 #include <iostuff.h> 158 #include <vstring.h> 159 160 /* Global library. */ 161 162 #include <mail_params.h> 163 #include <mail_proto.h> 164 #include <is_header.h> 165 #include <string_list.h> 166 #include <maps.h> 167 #include <ehlo_mask.h> 168 #include <lex_822.h> 169 #include <info_log_addr_form.h> 170 171 /* TLS library. */ 172 173 #include <tls.h> 174 175 /* Application-specific. */ 176 177 #include <postscreen.h> 178 179 /* 180 * Plan for future body processing. See smtp-sink.c. For now, we have no 181 * per-session push-back except for the single-character push-back that 182 * VSTREAM guarantees after we read one character. 183 */ 184 #define PSC_SMTPD_HAVE_PUSH_BACK(state) (0) 185 #define PSC_SMTPD_PUSH_BACK_CHAR(state, ch) \ 186 vstream_ungetc((state)->smtp_client_stream, (ch)) 187 #define PSC_SMTPD_NEXT_CHAR(state) \ 188 VSTREAM_GETC((state)->smtp_client_stream) 189 190 #define PSC_SMTPD_BUFFER_EMPTY(state) \ 191 (!PSC_SMTPD_HAVE_PUSH_BACK(state) \ 192 && vstream_peek((state)->smtp_client_stream) <= 0) 193 194 #define PSC_SMTPD_PEEK_DATA(state) \ 195 vstream_peek_data((state)->smtp_client_stream) 196 #define PSC_SMTPD_PEEK_LEN(state) \ 197 vstream_peek((state)->smtp_client_stream) 198 199 /* 200 * Dynamic reply strings. To minimize overhead we format these once. 201 */ 202 static char *psc_smtpd_greeting; /* smtp banner */ 203 static char *psc_smtpd_helo_reply; /* helo reply */ 204 static char *psc_smtpd_ehlo_reply_plain;/* multi-line ehlo reply, non-TLS */ 205 static char *psc_smtpd_ehlo_reply_tls; /* multi-line ehlo reply, with TLS */ 206 static char *psc_smtpd_timeout_reply; /* timeout reply */ 207 static char *psc_smtpd_421_reply; /* generic final_reply value */ 208 209 /* 210 * Forward declaration, needed by PSC_CLEAR_EVENT_REQUEST. 211 */ 212 static void psc_smtpd_time_event(int, void *); 213 static void psc_smtpd_read_event(int, void *); 214 215 /* 216 * Encapsulation. The STARTTLS, EHLO and AUTH command handlers temporarily 217 * suspend SMTP command events, send an asynchronous proxy request, and 218 * resume SMTP command events after receiving the asynchrounous proxy 219 * response (the EHLO handler must asynchronously talk to the auth server 220 * before it can announce the SASL mechanism list; the list can depend on 221 * the client IP address and on the presence on TLS encryption). 222 */ 223 #define PSC_RESUME_SMTP_CMD_EVENTS(state) do { \ 224 PSC_READ_EVENT_REQUEST2(vstream_fileno((state)->smtp_client_stream), \ 225 psc_smtpd_read_event, psc_smtpd_time_event, \ 226 (void *) (state), PSC_EFF_CMD_TIME_LIMIT); \ 227 if (!PSC_SMTPD_BUFFER_EMPTY(state)) \ 228 psc_smtpd_read_event(EVENT_READ, (void *) state); \ 229 } while (0) 230 231 #define PSC_SUSPEND_SMTP_CMD_EVENTS(state) \ 232 PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \ 233 psc_smtpd_time_event, (void *) (state)); 234 235 /* 236 * Make control characters and other non-text visible. 237 */ 238 #define PSC_SMTPD_ESCAPE_TEXT(dest, src, src_len, max_len) do { \ 239 ssize_t _s_len = (src_len); \ 240 ssize_t _m_len = (max_len); \ 241 (void) escape((dest), (src), _s_len < _m_len ? _s_len : _m_len); \ 242 } while (0) 243 244 /* 245 * Command parser support. 246 */ 247 #define PSC_SMTPD_NEXT_TOKEN(ptr) mystrtok(&(ptr), " ") 248 249 /* 250 * EHLO keyword filter 251 */ 252 static MAPS *psc_ehlo_discard_maps; 253 static int psc_ehlo_discard_mask; 254 255 /* 256 * Command editing filter. 257 */ 258 static DICT *psc_cmd_filter; 259 260 /* 261 * Encapsulation. We must not forget turn off input/timer events when we 262 * terminate the SMTP protocol engine. 263 * 264 * It would be safer to turn off input/timer events after each event, and to 265 * turn on input/timer events again when we want more input. But experience 266 * with the Postfix smtp-source and smtp-sink tools shows that this would 267 * noticeably increase the run-time cost. 268 */ 269 #define PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, event, reply) do { \ 270 PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \ 271 (event), (void *) (state)); \ 272 PSC_DROP_SESSION_STATE((state), (reply)); \ 273 } while (0) 274 275 #define PSC_CLEAR_EVENT_HANGUP(state, event) do { \ 276 PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \ 277 (event), (void *) (state)); \ 278 psc_hangup_event(state); \ 279 } while (0) 280 281 /* psc_helo_cmd - record HELO and respond */ 282 283 static int psc_helo_cmd(PSC_STATE *state, char *args) 284 { 285 char *helo_name = PSC_SMTPD_NEXT_TOKEN(args); 286 287 /* 288 * smtpd(8) incompatibility: we ignore extra words; smtpd(8) saves them. 289 */ 290 if (helo_name == 0) 291 return (PSC_SEND_REPLY(state, "501 Syntax: HELO hostname\r\n")); 292 293 PSC_STRING_UPDATE(state->helo_name, helo_name); 294 PSC_STRING_RESET(state->sender); 295 /* Don't downgrade state->protocol, in case some test depends on this. */ 296 return (PSC_SEND_REPLY(state, psc_smtpd_helo_reply)); 297 } 298 299 /* psc_smtpd_format_ehlo_reply - format EHLO response */ 300 301 static void psc_smtpd_format_ehlo_reply(VSTRING *buf, int discard_mask 302 /* , const char *sasl_mechanism_list */ ) 303 { 304 const char *myname = "psc_smtpd_format_ehlo_reply"; 305 int saved_len = 0; 306 307 if (msg_verbose) 308 msg_info("%s: discard_mask %s", myname, str_ehlo_mask(discard_mask)); 309 310 #define PSC_EHLO_APPEND(save, buf, fmt) do { \ 311 (save) = LEN(buf); \ 312 vstring_sprintf_append((buf), (fmt)); \ 313 } while (0) 314 315 #define PSC_EHLO_APPEND1(save, buf, fmt, arg1) do { \ 316 (save) = LEN(buf); \ 317 vstring_sprintf_append((buf), (fmt), (arg1)); \ 318 } while (0) 319 320 vstring_sprintf(psc_temp, "250-%s\r\n", var_myhostname); 321 if ((discard_mask & EHLO_MASK_SIZE) == 0) { 322 if (ENFORCING_SIZE_LIMIT(var_message_limit)) 323 PSC_EHLO_APPEND1(saved_len, psc_temp, "250-SIZE %lu\r\n", 324 (unsigned long) var_message_limit); 325 else 326 PSC_EHLO_APPEND(saved_len, psc_temp, "250-SIZE\r\n"); 327 } 328 if ((discard_mask & EHLO_MASK_VRFY) == 0 && var_disable_vrfy_cmd == 0) 329 PSC_EHLO_APPEND(saved_len, psc_temp, "250-VRFY\r\n"); 330 if ((discard_mask & EHLO_MASK_ETRN) == 0) 331 PSC_EHLO_APPEND(saved_len, psc_temp, "250-ETRN\r\n"); 332 if ((discard_mask & EHLO_MASK_STARTTLS) == 0 && var_psc_use_tls) 333 PSC_EHLO_APPEND(saved_len, psc_temp, "250-STARTTLS\r\n"); 334 #ifdef TODO_SASL_AUTH 335 if ((discard_mask & EHLO_MASK_AUTH) == 0 && sasl_mechanism_list 336 && (!var_psc_tls_auth_only || (discard_mask & EHLO_MASK_STARTTLS))) { 337 PSC_EHLO_APPEND1(saved_len, psc_temp, "AUTH %s", sasl_mechanism_list); 338 if (var_broken_auth_clients) 339 PSC_EHLO_APPEND1(saved_len, psc_temp, "AUTH=%s", sasl_mechanism_list); 340 } 341 #endif 342 if ((discard_mask & EHLO_MASK_ENHANCEDSTATUSCODES) == 0) 343 PSC_EHLO_APPEND(saved_len, psc_temp, "250-ENHANCEDSTATUSCODES\r\n"); 344 if ((discard_mask & EHLO_MASK_8BITMIME) == 0) 345 PSC_EHLO_APPEND(saved_len, psc_temp, "250-8BITMIME\r\n"); 346 if ((discard_mask & EHLO_MASK_DSN) == 0) 347 PSC_EHLO_APPEND(saved_len, psc_temp, "250-DSN\r\n"); 348 /* Fix 20140708: announce SMTPUTF8. */ 349 if (var_smtputf8_enable && (discard_mask & EHLO_MASK_SMTPUTF8) == 0) 350 PSC_EHLO_APPEND(saved_len, psc_temp, "250-SMTPUTF8\r\n"); 351 if ((discard_mask & EHLO_MASK_CHUNKING) == 0) 352 PSC_EHLO_APPEND(saved_len, psc_temp, "250-CHUNKING\r\n"); 353 STR(psc_temp)[saved_len + 3] = ' '; 354 } 355 356 /* psc_ehlo_cmd - record EHLO and respond */ 357 358 static int psc_ehlo_cmd(PSC_STATE *state, char *args) 359 { 360 char *helo_name = PSC_SMTPD_NEXT_TOKEN(args); 361 const char *ehlo_words; 362 int discard_mask; 363 char *reply; 364 365 /* 366 * smtpd(8) incompatibility: we ignore extra words; smtpd(8) saves them. 367 */ 368 if (helo_name == 0) 369 return (PSC_SEND_REPLY(state, "501 Syntax: EHLO hostname\r\n")); 370 371 PSC_STRING_UPDATE(state->helo_name, helo_name); 372 PSC_STRING_RESET(state->sender); 373 state->protocol = MAIL_PROTO_ESMTP; 374 375 /* 376 * smtpd(8) compatibility: dynamic reply filtering. 377 */ 378 if (psc_ehlo_discard_maps != 0 379 && (ehlo_words = psc_maps_find(psc_ehlo_discard_maps, 380 state->smtp_client_addr, 0)) != 0 381 && (discard_mask = ehlo_mask(ehlo_words)) != psc_ehlo_discard_mask) { 382 if (discard_mask && !(discard_mask & EHLO_MASK_SILENT)) 383 msg_info("[%s]%s: discarding EHLO keywords: %s", 384 PSC_CLIENT_ADDR_PORT(state), str_ehlo_mask(discard_mask)); 385 if (state->flags & PSC_STATE_FLAG_USING_TLS) 386 discard_mask |= EHLO_MASK_STARTTLS; 387 psc_smtpd_format_ehlo_reply(psc_temp, discard_mask); 388 reply = STR(psc_temp); 389 state->ehlo_discard_mask = discard_mask; 390 } else if (psc_ehlo_discard_maps && psc_ehlo_discard_maps->error) { 391 msg_fatal("%s lookup error for %s", 392 psc_ehlo_discard_maps->title, state->smtp_client_addr); 393 } else if (state->flags & PSC_STATE_FLAG_USING_TLS) { 394 reply = psc_smtpd_ehlo_reply_tls; 395 state->ehlo_discard_mask = psc_ehlo_discard_mask | EHLO_MASK_STARTTLS; 396 } else { 397 reply = psc_smtpd_ehlo_reply_plain; 398 state->ehlo_discard_mask = psc_ehlo_discard_mask; 399 } 400 return (PSC_SEND_REPLY(state, reply)); 401 } 402 403 /* psc_starttls_resume - resume the SMTP protocol after tlsproxy activation */ 404 405 static void psc_starttls_resume(int unused_event, void *context) 406 { 407 const char *myname = "psc_starttls_resume"; 408 PSC_STATE *state = (PSC_STATE *) context; 409 410 /* 411 * Reset SMTP server state if STARTTLS was successful. 412 */ 413 if (state->flags & PSC_STATE_FLAG_USING_TLS) { 414 /* Purge the push-back buffer, when implemented. */ 415 PSC_STRING_RESET(state->helo_name); 416 PSC_STRING_RESET(state->sender); 417 #ifdef TODO_SASL_AUTH 418 /* Reset SASL AUTH state. Dovecot responses may change. */ 419 #endif 420 } 421 422 /* 423 * Resume read/timeout events. If we still have unread input, resume the 424 * command processor immediately. 425 */ 426 PSC_RESUME_SMTP_CMD_EVENTS(state); 427 } 428 429 /* psc_starttls_cmd - activate the tlsproxy server */ 430 431 static int psc_starttls_cmd(PSC_STATE *state, char *args) 432 { 433 const char *myname = "psc_starttls_cmd"; 434 435 /* 436 * smtpd(8) incompatibility: we can't send a 4XX reply that TLS is 437 * unavailable when tlsproxy(8) detects the problem too late. 438 */ 439 if (PSC_SMTPD_NEXT_TOKEN(args) != 0) 440 return (PSC_SEND_REPLY(state, "501 Syntax: EHLO hostname\r\n")); 441 if (state->flags & PSC_STATE_FLAG_USING_TLS) 442 return (PSC_SEND_REPLY(state, 443 "554 5.5.1 Error: TLS already active\r\n")); 444 if (var_psc_use_tls == 0 || (state->ehlo_discard_mask & EHLO_MASK_STARTTLS)) 445 return (PSC_SEND_REPLY(state, 446 "502 5.5.1 Error: command not implemented\r\n")); 447 448 /* 449 * Suspend the SMTP protocol until psc_starttls_resume() is called. 450 */ 451 PSC_SUSPEND_SMTP_CMD_EVENTS(state); 452 psc_starttls_open(state, psc_starttls_resume); 453 return (0); 454 } 455 456 /* psc_extract_addr - extract MAIL/RCPT address, unquoted form */ 457 458 static char *psc_extract_addr(VSTRING *result, const char *string) 459 { 460 const unsigned char *cp = (const unsigned char *) string; 461 char *addr; 462 char *colon; 463 int stop_at; 464 int inquote = 0; 465 466 /* 467 * smtpd(8) incompatibility: we allow more invalid address forms, and we 468 * don't validate recipients. We are not going to deliver them so we 469 * won't have to worry about deliverability. This may have to change when 470 * we pass the socket to a real SMTP server and replay message envelope 471 * commands. 472 */ 473 474 /* Skip SP characters. */ 475 while (*cp && *cp == ' ') 476 cp++; 477 478 /* Choose the terminator for <addr> or bare addr. */ 479 if (*cp == '<') { 480 cp++; 481 stop_at = '>'; 482 } else { 483 stop_at = ' '; 484 } 485 486 /* Skip to terminator or end. */ 487 VSTRING_RESET(result); 488 for ( /* void */ ; *cp; cp++) { 489 if (!inquote && *cp == stop_at) 490 break; 491 if (*cp == '"') { 492 inquote = !inquote; 493 } else { 494 if (*cp == '\\' && *++cp == 0) 495 break; 496 VSTRING_ADDCH(result, *cp); 497 } 498 } 499 VSTRING_TERMINATE(result); 500 501 /* 502 * smtpd(8) compatibility: truncate deprecated route address form. This 503 * is primarily to simplify logfile analysis. 504 */ 505 addr = STR(result); 506 if (*addr == '@' && (colon = strchr(addr, ':')) != 0) 507 addr = colon + 1; 508 return (addr); 509 } 510 511 /* psc_mail_cmd - record MAIL and respond */ 512 513 static int psc_mail_cmd(PSC_STATE *state, char *args) 514 { 515 char *colon; 516 char *addr; 517 518 /* 519 * smtpd(8) incompatibility: we never reject the sender, and we ignore 520 * additional arguments. 521 */ 522 if (var_psc_helo_required && state->helo_name == 0) 523 return (PSC_SEND_REPLY(state, 524 "503 5.5.1 Error: send HELO/EHLO first\r\n")); 525 if (state->sender != 0) 526 return (PSC_SEND_REPLY(state, 527 "503 5.5.1 Error: nested MAIL command\r\n")); 528 if (args == 0 || (colon = strchr(args, ':')) == 0) 529 return (PSC_SEND_REPLY(state, 530 "501 5.5.4 Syntax: MAIL FROM:<address>\r\n")); 531 if ((addr = psc_extract_addr(psc_temp, colon + 1)) == 0) 532 return (PSC_SEND_REPLY(state, 533 "501 5.1.7 Bad sender address syntax\r\n")); 534 PSC_STRING_UPDATE(state->sender, addr); 535 return (PSC_SEND_REPLY(state, "250 2.1.0 Ok\r\n")); 536 } 537 538 /* psc_soften_reply - copy and soft-bounce a reply */ 539 540 static char *psc_soften_reply(const char *reply) 541 { 542 static VSTRING *buf = 0; 543 544 if (buf == 0) 545 buf = vstring_alloc(100); 546 vstring_strcpy(buf, reply); 547 if (reply[0] == '5') 548 STR(buf)[0] = '4'; 549 if (reply[4] == '5') 550 STR(buf)[4] = '4'; 551 return (STR(buf)); 552 } 553 554 /* psc_rcpt_cmd record RCPT and respond */ 555 556 static int psc_rcpt_cmd(PSC_STATE *state, char *args) 557 { 558 char *colon; 559 char *addr; 560 561 /* 562 * smtpd(8) incompatibility: we reject all recipients, and ignore 563 * additional arguments. 564 */ 565 if (state->sender == 0) 566 return (PSC_SEND_REPLY(state, 567 "503 5.5.1 Error: need MAIL command\r\n")); 568 if (args == 0 || (colon = strchr(args, ':')) == 0) 569 return (PSC_SEND_REPLY(state, 570 "501 5.5.4 Syntax: RCPT TO:<address>\r\n")); 571 if ((addr = psc_extract_addr(psc_temp, colon + 1)) == 0) 572 return (PSC_SEND_REPLY(state, 573 "501 5.1.3 Bad recipient address syntax\r\n")); 574 msg_info("NOQUEUE: reject: RCPT from [%s]:%s: %.*s; " 575 "from=<%s>, to=<%s>, proto=%s, helo=<%s>", 576 PSC_CLIENT_ADDR_PORT(state), 577 (int) strlen(state->rcpt_reply) - 2, 578 var_soft_bounce == 0 ? state->rcpt_reply : 579 psc_soften_reply(state->rcpt_reply), 580 info_log_addr_form_sender(state->sender), 581 info_log_addr_form_recipient(addr), state->protocol, 582 state->helo_name ? state->helo_name : ""); 583 return (PSC_SEND_REPLY(state, state->rcpt_reply)); 584 } 585 586 /* psc_data_cmd - respond to DATA and disconnect */ 587 588 static int psc_data_cmd(PSC_STATE *state, char *args) 589 { 590 const char myname[] = "psc_data_cmd"; 591 592 /* 593 * smtpd(8) incompatibility: postscreen(8) drops the connection, instead 594 * of waiting for the next command. Justification: postscreen(8) should 595 * never see DATA from a legitimate client, because 1) the server rejects 596 * every recipient, and 2) the server does not announce PIPELINING. 597 */ 598 msg_info("DATA without valid RCPT from [%s]:%s", 599 PSC_CLIENT_ADDR_PORT(state)); 600 if (PSC_SMTPD_NEXT_TOKEN(args) != 0) 601 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 602 psc_smtpd_time_event, 603 "501 5.5.4 Syntax: DATA\r\n"); 604 else if (state->sender == 0) 605 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 606 psc_smtpd_time_event, 607 "503 5.5.1 Error: need RCPT command\r\n"); 608 else 609 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 610 psc_smtpd_time_event, 611 "554 5.5.1 Error: no valid recipients\r\n"); 612 /* Caution: state is now a dangling pointer. */ 613 return (0); 614 } 615 616 /* psc_bdat_cmd - respond to BDAT and disconnect */ 617 618 static int psc_bdat_cmd(PSC_STATE *state, char *args) 619 { 620 const char *myname = "psc_bdat_cmd"; 621 622 /* 623 * smtpd(8) incompatibility: postscreen(8) drops the connection, instead 624 * of reading the entire BDAT chunk and staying in sync with the client. 625 * Justification: postscreen(8) should never see BDAT from a legitimate 626 * client, because 1) the server rejects every recipient, and 2) the 627 * server does not announce PIPELINING. 628 */ 629 msg_info("BDAT without valid RCPT from [%s]:%s", 630 PSC_CLIENT_ADDR_PORT(state)); 631 if (state->ehlo_discard_mask & EHLO_MASK_CHUNKING) 632 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 633 psc_smtpd_time_event, 634 "502 5.5.1 Error: command not implemented\r\n"); 635 else if (PSC_SMTPD_NEXT_TOKEN(args) == 0) 636 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 637 psc_smtpd_time_event, 638 "501 5.5.4 Syntax: BDAT count [LAST]\r\n"); 639 else if (state->sender == 0) 640 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 641 psc_smtpd_time_event, 642 "554 5.5.1 Error: need RCPT command\r\n"); 643 else 644 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 645 psc_smtpd_time_event, 646 "554 5.5.1 Error: no valid recipients\r\n"); 647 /* Caution: state is now a dangling pointer. */ 648 return (0); 649 } 650 651 /* psc_rset_cmd - reset, send 250 OK */ 652 653 static int psc_rset_cmd(PSC_STATE *state, char *unused_args) 654 { 655 PSC_STRING_RESET(state->sender); 656 return (PSC_SEND_REPLY(state, "250 2.0.0 Ok\r\n")); 657 } 658 659 /* psc_noop_cmd - respond to something */ 660 661 static int psc_noop_cmd(PSC_STATE *state, char *unused_args) 662 { 663 return (PSC_SEND_REPLY(state, "250 2.0.0 Ok\r\n")); 664 } 665 666 /* psc_vrfy_cmd - respond to VRFY */ 667 668 static int psc_vrfy_cmd(PSC_STATE *state, char *args) 669 { 670 671 /* 672 * smtpd(8) incompatibility: we reject all requests, and ignore 673 * additional arguments. 674 */ 675 if (PSC_SMTPD_NEXT_TOKEN(args) == 0) 676 return (PSC_SEND_REPLY(state, 677 "501 5.5.4 Syntax: VRFY address\r\n")); 678 if (var_psc_disable_vrfy) 679 return (PSC_SEND_REPLY(state, 680 "502 5.5.1 VRFY command is disabled\r\n")); 681 return (PSC_SEND_REPLY(state, state->rcpt_reply)); 682 } 683 684 /* psc_etrn_cmd - reset, send 250 OK */ 685 686 static int psc_etrn_cmd(PSC_STATE *state, char *args) 687 { 688 689 /* 690 * smtpd(8) incompatibility: we reject all requests, and ignore 691 * additional arguments. 692 */ 693 if (var_psc_helo_required && state->helo_name == 0) 694 return (PSC_SEND_REPLY(state, 695 "503 5.5.1 Error: send HELO/EHLO first\r\n")); 696 if (PSC_SMTPD_NEXT_TOKEN(args) == 0) 697 return (PSC_SEND_REPLY(state, 698 "500 Syntax: ETRN domain\r\n")); 699 return (PSC_SEND_REPLY(state, "458 Unable to queue messages\r\n")); 700 } 701 702 /* psc_quit_cmd - respond to QUIT and disconnect */ 703 704 static int psc_quit_cmd(PSC_STATE *state, char *unused_args) 705 { 706 const char *myname = "psc_quit_cmd"; 707 708 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event, 709 "221 2.0.0 Bye\r\n"); 710 /* Caution: state is now a dangling pointer. */ 711 return (0); 712 } 713 714 /* psc_smtpd_time_event - handle per-session time limit */ 715 716 static void psc_smtpd_time_event(int event, void *context) 717 { 718 const char *myname = "psc_smtpd_time_event"; 719 PSC_STATE *state = (PSC_STATE *) context; 720 721 if (msg_verbose > 1) 722 msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s", 723 myname, psc_post_queue_length, psc_check_queue_length, 724 event, vstream_fileno(state->smtp_client_stream), 725 state->smtp_client_addr, state->smtp_client_port, 726 psc_print_state_flags(state->flags, myname)); 727 728 msg_info("COMMAND TIME LIMIT from [%s]:%s after %s", 729 PSC_CLIENT_ADDR_PORT(state), state->where); 730 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event, 731 psc_smtpd_timeout_reply); 732 } 733 734 /* 735 * The table of all SMTP commands that we know. 736 */ 737 typedef struct { 738 const char *name; 739 int (*action) (PSC_STATE *, char *); 740 int flags; /* see below */ 741 } PSC_SMTPD_COMMAND; 742 743 #define PSC_SMTPD_CMD_FLAG_NONE (0) /* no flags (i.e. disabled) */ 744 #define PSC_SMTPD_CMD_FLAG_ENABLE (1<<0) /* command is enabled */ 745 #define PSC_SMTPD_CMD_FLAG_DESTROY (1<<1) /* dangling pointer alert */ 746 #define PSC_SMTPD_CMD_FLAG_PRE_TLS (1<<2) /* allowed with mandatory TLS */ 747 #define PSC_SMTPD_CMD_FLAG_SUSPEND (1<<3) /* suspend command engine */ 748 #define PSC_SMTPD_CMD_FLAG_HAS_PAYLOAD (1<<4) /* command has payload */ 749 750 static const PSC_SMTPD_COMMAND command_table[] = { 751 "HELO", psc_helo_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS, 752 "EHLO", psc_ehlo_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS, 753 "STARTTLS", psc_starttls_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS | PSC_SMTPD_CMD_FLAG_SUSPEND, 754 "XCLIENT", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_NONE, 755 "XFORWARD", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_NONE, 756 "AUTH", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_NONE, 757 "MAIL", psc_mail_cmd, PSC_SMTPD_CMD_FLAG_ENABLE, 758 "RCPT", psc_rcpt_cmd, PSC_SMTPD_CMD_FLAG_ENABLE, 759 "DATA", psc_data_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_DESTROY, 760 /* ".", psc_dot_cmd, PSC_SMTPD_CMD_FLAG_NONE, */ 761 "BDAT", psc_bdat_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_DESTROY | PSC_SMTPD_CMD_FLAG_HAS_PAYLOAD, 762 "RSET", psc_rset_cmd, PSC_SMTPD_CMD_FLAG_ENABLE, 763 "NOOP", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS, 764 "VRFY", psc_vrfy_cmd, PSC_SMTPD_CMD_FLAG_ENABLE, 765 "ETRN", psc_etrn_cmd, PSC_SMTPD_CMD_FLAG_ENABLE, 766 "QUIT", psc_quit_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_DESTROY | PSC_SMTPD_CMD_FLAG_PRE_TLS, 767 0, 768 }; 769 770 /* psc_smtpd_read_event - pseudo responder */ 771 772 static void psc_smtpd_read_event(int event, void *context) 773 { 774 const char *myname = "psc_smtpd_read_event"; 775 PSC_STATE *state = (PSC_STATE *) context; 776 time_t *expire_time = state->client_info->expire_time; 777 int ch; 778 struct cmd_trans { 779 int state; 780 int want; 781 int next_state; 782 }; 783 const char *saved_where; 784 785 #define PSC_SMTPD_CMD_ST_ANY 0 786 #define PSC_SMTPD_CMD_ST_CR 1 787 #define PSC_SMTPD_CMD_ST_CR_LF 2 788 789 static const struct cmd_trans cmd_trans[] = { 790 PSC_SMTPD_CMD_ST_ANY, '\r', PSC_SMTPD_CMD_ST_CR, 791 PSC_SMTPD_CMD_ST_CR, '\n', PSC_SMTPD_CMD_ST_CR_LF, 792 0, 0, 0, 793 }; 794 const struct cmd_trans *transp; 795 char *cmd_buffer_ptr; 796 char *command; 797 const PSC_SMTPD_COMMAND *cmdp; 798 int write_stat; 799 800 if (msg_verbose > 1) 801 msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s", 802 myname, psc_post_queue_length, psc_check_queue_length, 803 event, vstream_fileno(state->smtp_client_stream), 804 state->smtp_client_addr, state->smtp_client_port, 805 psc_print_state_flags(state->flags, myname)); 806 807 /* 808 * Basic liveness requirements. 809 * 810 * Drain all input in the VSTREAM buffer, otherwise this socket will not 811 * receive further read event notification until the client disconnects! 812 * 813 * To suspend this loop temporarily before the buffer is drained, use the 814 * PSC_SUSPEND_SMTP_CMD_EVENTS() and PSC_RESUME_SMTP_CMD_EVENTS() macros, 815 * and set the PSC_SMTPD_CMD_FLAG_SUSPEND flag in the command table. 816 * 817 * Don't try to read input before it has arrived, otherwise we would starve 818 * the pseudo threads of other sessions. Get out of here as soon as the 819 * VSTREAM read buffer dries up. Do not look for more input in kernel 820 * buffers. That input wasn't likely there when psc_smtpd_read_event() 821 * was called. Also, yielding the pseudo thread will improve fairness for 822 * other pseudo threads. 823 */ 824 825 /* 826 * Note: on entry into this function the VSTREAM buffer may or may not be 827 * empty, so we test the "no more input" condition at the bottom of the 828 * loops. 829 */ 830 for (;;) { 831 832 /* 833 * Read one command line, possibly one fragment at a time. 834 */ 835 for (;;) { 836 837 if ((ch = PSC_SMTPD_NEXT_CHAR(state)) == VSTREAM_EOF) { 838 PSC_CLEAR_EVENT_HANGUP(state, psc_smtpd_time_event); 839 return; 840 } 841 842 /* 843 * Sanity check. We don't want to store infinitely long commands. 844 */ 845 if (state->read_state == PSC_SMTPD_CMD_ST_ANY 846 && VSTRING_LEN(state->cmd_buffer) >= var_line_limit) { 847 msg_info("COMMAND LENGTH LIMIT from [%s]:%s after %s", 848 PSC_CLIENT_ADDR_PORT(state), state->where); 849 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event, 850 psc_smtpd_421_reply); 851 return; 852 } 853 VSTRING_ADDCH(state->cmd_buffer, ch); 854 855 /* 856 * Try to match the current character desired by the state 857 * machine. If that fails, try to restart the machine with a 858 * match for its first state. Like smtpd(8), we understand lines 859 * ending in <CR><LF> and bare <LF>. Unlike smtpd(8), we may 860 * treat lines ending in bare <LF> as an offense. 861 */ 862 for (transp = cmd_trans; transp->state != state->read_state; transp++) 863 if (transp->want == 0) 864 msg_panic("%s: command_read: unknown state: %d", 865 myname, state->read_state); 866 if (ch == transp->want) 867 state->read_state = transp->next_state; 868 else if (ch == cmd_trans[0].want) 869 state->read_state = cmd_trans[0].next_state; 870 else 871 state->read_state = PSC_SMTPD_CMD_ST_ANY; 872 if (state->read_state == PSC_SMTPD_CMD_ST_CR_LF) { 873 vstring_truncate(state->cmd_buffer, 874 VSTRING_LEN(state->cmd_buffer) - 2); 875 break; 876 } 877 878 /* 879 * Bare newline test. 880 */ 881 if (ch == '\n') { 882 if ((state->flags & PSC_STATE_MASK_BARLF_TODO_SKIP) 883 == PSC_STATE_FLAG_BARLF_TODO) { 884 PSC_SMTPD_ESCAPE_TEXT(psc_temp, STR(state->cmd_buffer), 885 VSTRING_LEN(state->cmd_buffer) - 1, 100); 886 msg_info("BARE NEWLINE from [%s]:%s after %s", 887 PSC_CLIENT_ADDR_PORT(state), STR(psc_temp)); 888 PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_BARLF_FAIL); 889 PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_BARLF_PASS); 890 expire_time[PSC_TINDX_BARLF] = PSC_TIME_STAMP_DISABLED; /* XXX */ 891 /* Skip this test for the remainder of this session. */ 892 PSC_SKIP_SESSION_STATE(state, "bare newline test", 893 PSC_STATE_FLAG_BARLF_SKIP); 894 switch (psc_barlf_action) { 895 case PSC_ACT_DROP: 896 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 897 psc_smtpd_time_event, 898 "521 5.5.1 Protocol error\r\n"); 899 return; 900 case PSC_ACT_ENFORCE: 901 PSC_ENFORCE_SESSION_STATE(state, 902 "550 5.5.1 Protocol error\r\n"); 903 break; 904 case PSC_ACT_IGNORE: 905 PSC_UNFAIL_SESSION_STATE(state, 906 PSC_STATE_FLAG_BARLF_FAIL); 907 /* Temporarily whitelist until something expires. */ 908 PSC_PASS_SESSION_STATE(state, "bare newline test", 909 PSC_STATE_FLAG_BARLF_PASS); 910 expire_time[PSC_TINDX_BARLF] = event_time() + psc_min_ttl; 911 break; 912 default: 913 msg_panic("%s: unknown bare_newline action value %d", 914 myname, psc_barlf_action); 915 } 916 } 917 vstring_truncate(state->cmd_buffer, 918 VSTRING_LEN(state->cmd_buffer) - 1); 919 break; 920 } 921 922 /* 923 * Yield this pseudo thread when the VSTREAM buffer is empty in 924 * the middle of a command. 925 * 926 * XXX Do not reset the read timeout. The entire command must be 927 * received within the time limit. 928 */ 929 if (PSC_SMTPD_BUFFER_EMPTY(state)) 930 return; 931 } 932 933 /* 934 * Terminate the command buffer, and apply the last-resort command 935 * editing workaround. 936 */ 937 VSTRING_TERMINATE(state->cmd_buffer); 938 if (psc_cmd_filter != 0) { 939 const char *cp; 940 941 for (cp = STR(state->cmd_buffer); *cp && IS_SPACE_TAB(*cp); cp++) 942 /* void */ ; 943 if ((cp = psc_dict_get(psc_cmd_filter, cp)) != 0) { 944 msg_info("[%s]:%s: replacing command \"%.100s\" with \"%.100s\"", 945 state->smtp_client_addr, state->smtp_client_port, 946 STR(state->cmd_buffer), cp); 947 vstring_strcpy(state->cmd_buffer, cp); 948 } else if (psc_cmd_filter->error != 0) { 949 msg_fatal("%s:%s lookup error for \"%.100s\"", 950 psc_cmd_filter->type, psc_cmd_filter->name, 951 STR(state->cmd_buffer)); 952 } 953 } 954 955 /* 956 * Reset the command buffer write pointer and state machine in 957 * preparation for the next command. For this to work as expected, 958 * VSTRING_RESET() must be non-destructive. We just can't ask for the 959 * VSTRING_LEN() and vstring_end() results. 960 */ 961 state->read_state = PSC_SMTPD_CMD_ST_ANY; 962 VSTRING_RESET(state->cmd_buffer); 963 964 /* 965 * Process the command line. 966 * 967 * Caution: some command handlers terminate the session and destroy the 968 * session state structure. When this happens we must leave the SMTP 969 * engine to avoid a dangling pointer problem. 970 */ 971 cmd_buffer_ptr = STR(state->cmd_buffer); 972 if (msg_verbose) 973 msg_info("< [%s]:%s: %s", state->smtp_client_addr, 974 state->smtp_client_port, cmd_buffer_ptr); 975 976 /* Parse the command name. */ 977 if ((command = PSC_SMTPD_NEXT_TOKEN(cmd_buffer_ptr)) == 0) 978 command = ""; 979 980 /* 981 * The non-SMTP, PIPELINING and command COUNT tests depend on the 982 * client command handler. 983 * 984 * Caution: cmdp->name and cmdp->action may be null on loop exit. 985 */ 986 saved_where = state->where; 987 state->where = PSC_SMTPD_CMD_UNIMPL; 988 for (cmdp = command_table; cmdp->name != 0; cmdp++) { 989 if (strcasecmp(command, cmdp->name) == 0) { 990 state->where = cmdp->name; 991 break; 992 } 993 } 994 995 if ((state->flags & PSC_STATE_FLAG_SMTPD_X21) 996 && cmdp->action != psc_quit_cmd) { 997 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event, 998 state->final_reply); 999 return; 1000 } 1001 /* Non-SMTP command test. */ 1002 if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_SKIP) 1003 == PSC_STATE_FLAG_NSMTP_TODO && cmdp->name == 0 1004 && (is_header(command) 1005 /* Ignore forbid_cmds lookup errors. Non-critical feature. */ 1006 || (*var_psc_forbid_cmds 1007 && string_list_match(psc_forbid_cmds, command)))) { 1008 printable(command, '?'); 1009 PSC_SMTPD_ESCAPE_TEXT(psc_temp, cmd_buffer_ptr, 1010 strlen(cmd_buffer_ptr), 100); 1011 msg_info("NON-SMTP COMMAND from [%s]:%s after %s: %.100s %s", 1012 PSC_CLIENT_ADDR_PORT(state), saved_where, 1013 command, STR(psc_temp)); 1014 PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_FAIL); 1015 PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_PASS); 1016 expire_time[PSC_TINDX_NSMTP] = PSC_TIME_STAMP_DISABLED; /* XXX */ 1017 /* Skip this test for the remainder of this SMTP session. */ 1018 PSC_SKIP_SESSION_STATE(state, "non-smtp test", 1019 PSC_STATE_FLAG_NSMTP_SKIP); 1020 switch (psc_nsmtp_action) { 1021 case PSC_ACT_DROP: 1022 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 1023 psc_smtpd_time_event, 1024 "521 5.7.0 Error: I can break rules, too. Goodbye.\r\n"); 1025 return; 1026 case PSC_ACT_ENFORCE: 1027 PSC_ENFORCE_SESSION_STATE(state, 1028 "550 5.5.1 Protocol error\r\n"); 1029 break; 1030 case PSC_ACT_IGNORE: 1031 PSC_UNFAIL_SESSION_STATE(state, 1032 PSC_STATE_FLAG_NSMTP_FAIL); 1033 /* Temporarily whitelist until something else expires. */ 1034 PSC_PASS_SESSION_STATE(state, "non-smtp test", 1035 PSC_STATE_FLAG_NSMTP_PASS); 1036 expire_time[PSC_TINDX_NSMTP] = event_time() + psc_min_ttl; 1037 break; 1038 default: 1039 msg_panic("%s: unknown non_smtp_command action value %d", 1040 myname, psc_nsmtp_action); 1041 } 1042 } 1043 /* Command PIPELINING test. */ 1044 if ((cmdp->flags & PSC_SMTPD_CMD_FLAG_HAS_PAYLOAD) == 0 1045 && (state->flags & PSC_STATE_MASK_PIPEL_TODO_SKIP) 1046 == PSC_STATE_FLAG_PIPEL_TODO && !PSC_SMTPD_BUFFER_EMPTY(state)) { 1047 printable(command, '?'); 1048 PSC_SMTPD_ESCAPE_TEXT(psc_temp, PSC_SMTPD_PEEK_DATA(state), 1049 PSC_SMTPD_PEEK_LEN(state), 100); 1050 msg_info("COMMAND PIPELINING from [%s]:%s after %.100s: %s", 1051 PSC_CLIENT_ADDR_PORT(state), command, STR(psc_temp)); 1052 PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_FAIL); 1053 PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_PASS); 1054 expire_time[PSC_TINDX_PIPEL] = PSC_TIME_STAMP_DISABLED; /* XXX */ 1055 /* Skip this test for the remainder of this SMTP session. */ 1056 PSC_SKIP_SESSION_STATE(state, "pipelining test", 1057 PSC_STATE_FLAG_PIPEL_SKIP); 1058 switch (psc_pipel_action) { 1059 case PSC_ACT_DROP: 1060 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 1061 psc_smtpd_time_event, 1062 "521 5.5.1 Protocol error\r\n"); 1063 return; 1064 case PSC_ACT_ENFORCE: 1065 PSC_ENFORCE_SESSION_STATE(state, 1066 "550 5.5.1 Protocol error\r\n"); 1067 break; 1068 case PSC_ACT_IGNORE: 1069 PSC_UNFAIL_SESSION_STATE(state, 1070 PSC_STATE_FLAG_PIPEL_FAIL); 1071 /* Temporarily whitelist until something else expires. */ 1072 PSC_PASS_SESSION_STATE(state, "pipelining test", 1073 PSC_STATE_FLAG_PIPEL_PASS); 1074 expire_time[PSC_TINDX_PIPEL] = event_time() + psc_min_ttl; 1075 break; 1076 default: 1077 msg_panic("%s: unknown pipelining action value %d", 1078 myname, psc_pipel_action); 1079 } 1080 } 1081 1082 /* 1083 * The following tests don't pass until the client gets all the way 1084 * to the RCPT TO command. However, the client can still fail these 1085 * tests with some later command. 1086 */ 1087 if (cmdp->action == psc_rcpt_cmd) { 1088 if ((state->flags & PSC_STATE_MASK_BARLF_TODO_PASS_FAIL) 1089 == PSC_STATE_FLAG_BARLF_TODO) { 1090 PSC_PASS_SESSION_STATE(state, "bare newline test", 1091 PSC_STATE_FLAG_BARLF_PASS); 1092 /* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */ 1093 expire_time[PSC_TINDX_BARLF] = event_time() + var_psc_barlf_ttl; 1094 } 1095 if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL) 1096 == PSC_STATE_FLAG_NSMTP_TODO) { 1097 PSC_PASS_SESSION_STATE(state, "non-smtp test", 1098 PSC_STATE_FLAG_NSMTP_PASS); 1099 /* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */ 1100 expire_time[PSC_TINDX_NSMTP] = event_time() + var_psc_nsmtp_ttl; 1101 } 1102 if ((state->flags & PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL) 1103 == PSC_STATE_FLAG_PIPEL_TODO) { 1104 PSC_PASS_SESSION_STATE(state, "pipelining test", 1105 PSC_STATE_FLAG_PIPEL_PASS); 1106 /* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */ 1107 expire_time[PSC_TINDX_PIPEL] = event_time() + var_psc_pipel_ttl; 1108 } 1109 } 1110 /* Command COUNT limit test. */ 1111 if (++state->command_count > var_psc_cmd_count 1112 && cmdp->action != psc_quit_cmd) { 1113 msg_info("COMMAND COUNT LIMIT from [%s]:%s after %s", 1114 PSC_CLIENT_ADDR_PORT(state), saved_where); 1115 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event, 1116 psc_smtpd_421_reply); 1117 return; 1118 } 1119 /* Finally, execute the command. */ 1120 if (cmdp->name == 0 || (cmdp->flags & PSC_SMTPD_CMD_FLAG_ENABLE) == 0) { 1121 write_stat = PSC_SEND_REPLY(state, 1122 "502 5.5.2 Error: command not recognized\r\n"); 1123 } else if (var_psc_enforce_tls 1124 && (state->flags & PSC_STATE_FLAG_USING_TLS) == 0 1125 && (cmdp->flags & PSC_SMTPD_CMD_FLAG_PRE_TLS) == 0) { 1126 write_stat = PSC_SEND_REPLY(state, 1127 "530 5.7.0 Must issue a STARTTLS command first\r\n"); 1128 } else { 1129 write_stat = cmdp->action(state, cmd_buffer_ptr); 1130 if (cmdp->flags & PSC_SMTPD_CMD_FLAG_DESTROY) 1131 return; 1132 } 1133 1134 /* 1135 * Terminate the session after a write error. 1136 */ 1137 if (write_stat < 0) { 1138 PSC_CLEAR_EVENT_HANGUP(state, psc_smtpd_time_event); 1139 return; 1140 } 1141 1142 /* 1143 * We're suspended, waiting for some external event to happen. 1144 * Hopefully, someone will call us back to process the remainder of 1145 * the pending input, otherwise we could hang. 1146 */ 1147 if (cmdp->flags & PSC_SMTPD_CMD_FLAG_SUSPEND) 1148 return; 1149 1150 /* 1151 * Reset the command read timeout before reading the next command. 1152 */ 1153 event_request_timer(psc_smtpd_time_event, (void *) state, 1154 PSC_EFF_CMD_TIME_LIMIT); 1155 1156 /* 1157 * Yield this pseudo thread when the VSTREAM buffer is empty. 1158 */ 1159 if (PSC_SMTPD_BUFFER_EMPTY(state)) 1160 return; 1161 } 1162 } 1163 1164 /* psc_smtpd_tests - per-session deep protocol test initialization */ 1165 1166 void psc_smtpd_tests(PSC_STATE *state) 1167 { 1168 static char *myname = "psc_smtpd_tests"; 1169 1170 /* 1171 * Report errors and progress in the context of this test. 1172 */ 1173 PSC_BEGIN_TESTS(state, "tests after SMTP handshake"); 1174 1175 /* 1176 * Initialize per-session state that is used only by the dummy engine: 1177 * the command read buffer and the command read state machine. 1178 */ 1179 state->cmd_buffer = vstring_alloc(100); 1180 state->read_state = PSC_SMTPD_CMD_ST_ANY; 1181 1182 /* 1183 * Disable all after-220 tests when we need to reply with 421 and hang up 1184 * after reading the next SMTP client command. 1185 * 1186 * Opportunistically make postscreen more useful, by turning on all 1187 * after-220 tests when a bad client failed a before-220 test. 1188 * 1189 * Otherwise, only apply the explicitly-configured after-220 tests. 1190 */ 1191 if (state->flags & PSC_STATE_FLAG_SMTPD_X21) { 1192 state->flags &= ~PSC_STATE_MASK_SMTPD_TODO; 1193 } else if (state->flags & PSC_STATE_MASK_ANY_FAIL) { 1194 state->flags |= PSC_STATE_MASK_SMTPD_TODO; 1195 } 1196 1197 /* 1198 * Send no SMTP banner to pregreeting clients. This eliminates a lot of 1199 * "NON-SMTP COMMAND" events, and improves sender/recipient logging. 1200 */ 1201 if ((state->flags & PSC_STATE_FLAG_PREGR_FAIL) == 0 1202 && PSC_SEND_REPLY(state, psc_smtpd_greeting) != 0) { 1203 psc_hangup_event(state); 1204 return; 1205 } 1206 1207 /* 1208 * Wait for the client to respond. 1209 */ 1210 PSC_READ_EVENT_REQUEST2(vstream_fileno(state->smtp_client_stream), 1211 psc_smtpd_read_event, psc_smtpd_time_event, 1212 (void *) state, PSC_EFF_CMD_TIME_LIMIT); 1213 } 1214 1215 /* psc_smtpd_init - per-process deep protocol test initialization */ 1216 1217 void psc_smtpd_init(void) 1218 { 1219 1220 /* 1221 * Initialize the server banner. 1222 */ 1223 vstring_sprintf(psc_temp, "220 %s\r\n", var_smtpd_banner); 1224 psc_smtpd_greeting = mystrdup(STR(psc_temp)); 1225 1226 /* 1227 * Initialize the HELO reply. 1228 */ 1229 vstring_sprintf(psc_temp, "250 %s\r\n", var_myhostname); 1230 psc_smtpd_helo_reply = mystrdup(STR(psc_temp)); 1231 1232 /* 1233 * STARTTLS support. Note the complete absence of #ifdef USE_TLS 1234 * throughout the postscreen(8) source code. If Postfix is built without 1235 * TLS support, then the TLS proxy will simply report that TLS is not 1236 * available, and conventional error handling will take care of the 1237 * issue. 1238 * 1239 * Legacy code copied from smtpd(8). The pre-fabricated EHLO reply depends 1240 * on this. 1241 */ 1242 if (*var_psc_tls_level) { 1243 switch (tls_level_lookup(var_psc_tls_level)) { 1244 default: 1245 msg_fatal("Invalid TLS level \"%s\"", var_psc_tls_level); 1246 /* NOTREACHED */ 1247 break; 1248 case TLS_LEV_SECURE: 1249 case TLS_LEV_VERIFY: 1250 case TLS_LEV_FPRINT: 1251 msg_warn("%s: unsupported TLS level \"%s\", using \"encrypt\"", 1252 VAR_PSC_TLS_LEVEL, var_psc_tls_level); 1253 /* FALLTHROUGH */ 1254 case TLS_LEV_ENCRYPT: 1255 var_psc_enforce_tls = var_psc_use_tls = 1; 1256 break; 1257 case TLS_LEV_MAY: 1258 var_psc_enforce_tls = 0; 1259 var_psc_use_tls = 1; 1260 break; 1261 case TLS_LEV_NONE: 1262 var_psc_enforce_tls = var_psc_use_tls = 0; 1263 break; 1264 } 1265 } 1266 var_psc_use_tls = var_psc_use_tls || var_psc_enforce_tls; 1267 #ifdef TODO_SASL_AUTH 1268 var_psc_tls_auth_only = var_psc_tls_auth_only || var_psc_enforce_tls; 1269 #endif 1270 1271 /* 1272 * Initialize the EHLO reply. Once for plaintext sessions, and once for 1273 * TLS sessions. 1274 */ 1275 psc_smtpd_format_ehlo_reply(psc_temp, psc_ehlo_discard_mask); 1276 psc_smtpd_ehlo_reply_plain = mystrdup(STR(psc_temp)); 1277 1278 psc_smtpd_format_ehlo_reply(psc_temp, 1279 psc_ehlo_discard_mask | EHLO_MASK_STARTTLS); 1280 psc_smtpd_ehlo_reply_tls = mystrdup(STR(psc_temp)); 1281 1282 /* 1283 * Initialize the 421 timeout reply. 1284 */ 1285 vstring_sprintf(psc_temp, "421 4.4.2 %s Error: timeout exceeded\r\n", 1286 var_myhostname); 1287 psc_smtpd_timeout_reply = mystrdup(STR(psc_temp)); 1288 1289 /* 1290 * Initialize the generic 421 reply. 1291 */ 1292 vstring_sprintf(psc_temp, "421 %s Service unavailable - try again later\r\n", 1293 var_myhostname); 1294 psc_smtpd_421_reply = mystrdup(STR(psc_temp)); 1295 1296 /* 1297 * Initialize the reply footer. 1298 */ 1299 if (*var_psc_rej_footer || *var_psc_rej_ftr_maps) 1300 psc_expand_init(); 1301 } 1302 1303 /* psc_smtpd_pre_jail_init - per-process deep protocol test initialization */ 1304 1305 void psc_smtpd_pre_jail_init(void) 1306 { 1307 1308 /* 1309 * Determine what server ESMTP features to suppress, typically to avoid 1310 * inter-operability problems. We do the default filter here, and 1311 * determine client-dependent filtering on the fly. 1312 * 1313 * XXX Bugger. This means we have to restart when the table changes! 1314 */ 1315 if (*var_psc_ehlo_dis_maps) 1316 psc_ehlo_discard_maps = maps_create(VAR_PSC_EHLO_DIS_MAPS, 1317 var_psc_ehlo_dis_maps, 1318 DICT_FLAG_LOCK); 1319 psc_ehlo_discard_mask = ehlo_mask(var_psc_ehlo_dis_words); 1320 1321 /* 1322 * Last-resort command editing support. 1323 */ 1324 if (*var_psc_cmd_filter) 1325 psc_cmd_filter = dict_open(var_psc_cmd_filter, O_RDONLY, 1326 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX); 1327 1328 /* 1329 * SMTP server reply footer. 1330 */ 1331 if (*var_psc_rej_ftr_maps) 1332 pcs_send_pre_jail_init(); 1333 } 1334