1 /* $NetBSD: postscreen_smtpd.c,v 1.6 2025/02/25 19:15:48 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 allowlisted 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 asynchronous 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 5.5.4 Syntax: STARTTLS\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 MAIL 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. Note: at this point, state->cmd_buffer is 880 * not null-terminated and may contain embedded null bytes. 881 */ 882 if (ch == '\n') { 883 if ((state->flags & PSC_STATE_MASK_BARLF_TODO_SKIP) 884 == PSC_STATE_FLAG_BARLF_TODO) { 885 PSC_SMTPD_ESCAPE_TEXT(psc_temp, STR(state->cmd_buffer), 886 VSTRING_LEN(state->cmd_buffer) - 1, 100); 887 msg_info("BARE NEWLINE from [%s]:%s after %s", 888 PSC_CLIENT_ADDR_PORT(state), STR(psc_temp)); 889 PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_BARLF_FAIL); 890 PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_BARLF_PASS); 891 expire_time[PSC_TINDX_BARLF] = PSC_TIME_STAMP_DISABLED; /* XXX */ 892 /* Skip this test for the remainder of this session. */ 893 PSC_SKIP_SESSION_STATE(state, "bare newline test", 894 PSC_STATE_FLAG_BARLF_SKIP); 895 switch (psc_barlf_action) { 896 case PSC_ACT_DROP: 897 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 898 psc_smtpd_time_event, 899 "521 5.5.1 Protocol error\r\n"); 900 return; 901 case PSC_ACT_ENFORCE: 902 PSC_ENFORCE_SESSION_STATE(state, 903 "550 5.5.1 Protocol error\r\n"); 904 break; 905 case PSC_ACT_IGNORE: 906 PSC_UNFAIL_SESSION_STATE(state, 907 PSC_STATE_FLAG_BARLF_FAIL); 908 /* Temporarily allowlist until something expires. */ 909 PSC_PASS_SESSION_STATE(state, "bare newline test", 910 PSC_STATE_FLAG_BARLF_PASS); 911 expire_time[PSC_TINDX_BARLF] = event_time() + psc_min_ttl; 912 break; 913 default: 914 msg_panic("%s: unknown bare_newline action value %d", 915 myname, psc_barlf_action); 916 } 917 } 918 vstring_truncate(state->cmd_buffer, 919 VSTRING_LEN(state->cmd_buffer) - 1); 920 break; 921 } 922 923 /* 924 * Yield this pseudo thread when the VSTREAM buffer is empty in 925 * the middle of a command. 926 * 927 * XXX Do not reset the read timeout. The entire command must be 928 * received within the time limit. 929 */ 930 if (PSC_SMTPD_BUFFER_EMPTY(state)) 931 return; 932 } 933 934 /* 935 * Avoid complaints from Postfix maps about malformed content. Note: 936 * this will stop at the first null byte, just like the code that 937 * parses the command name or command arguments. 938 */ 939 #define PSC_BAD_UTF8(str) \ 940 (var_smtputf8_enable && !valid_utf8_stringz(str)) 941 942 /* 943 * Terminate the command buffer, and apply the last-resort command 944 * editing workaround. 945 */ 946 VSTRING_TERMINATE(state->cmd_buffer); 947 if (psc_cmd_filter != 0 && !PSC_BAD_UTF8(STR(state->cmd_buffer))) { 948 const char *cp; 949 950 for (cp = STR(state->cmd_buffer); *cp && IS_SPACE_TAB(*cp); cp++) 951 /* void */ ; 952 if ((cp = psc_dict_get(psc_cmd_filter, cp)) != 0) { 953 msg_info("[%s]:%s: replacing command \"%.100s\" with \"%.100s\"", 954 state->smtp_client_addr, state->smtp_client_port, 955 STR(state->cmd_buffer), cp); 956 vstring_strcpy(state->cmd_buffer, cp); 957 } else if (psc_cmd_filter->error != 0) { 958 msg_fatal("%s:%s lookup error for \"%.100s\"", 959 psc_cmd_filter->type, psc_cmd_filter->name, 960 STR(state->cmd_buffer)); 961 } 962 } 963 964 /* 965 * Reset the command buffer write pointer and state machine in 966 * preparation for the next command. For this to work as expected, 967 * VSTRING_RESET() must be non-destructive. We just can't ask for the 968 * VSTRING_LEN() and vstring_end() results. 969 */ 970 state->read_state = PSC_SMTPD_CMD_ST_ANY; 971 VSTRING_RESET(state->cmd_buffer); 972 973 /* 974 * Process the command line. 975 * 976 * Caution: some command handlers terminate the session and destroy the 977 * session state structure. When this happens we must leave the SMTP 978 * engine to avoid a dangling pointer problem. 979 */ 980 cmd_buffer_ptr = STR(state->cmd_buffer); 981 if (msg_verbose) 982 msg_info("< [%s]:%s: %s", state->smtp_client_addr, 983 state->smtp_client_port, cmd_buffer_ptr); 984 985 /* Parse the command name. */ 986 if ((command = PSC_SMTPD_NEXT_TOKEN(cmd_buffer_ptr)) == 0) 987 command = ""; 988 989 /* 990 * The non-SMTP, PIPELINING and command COUNT tests depend on the 991 * client command handler. 992 * 993 * Caution: cmdp->name and cmdp->action may be null on loop exit. 994 */ 995 saved_where = state->where; 996 state->where = PSC_SMTPD_CMD_UNIMPL; 997 for (cmdp = command_table; cmdp->name != 0; cmdp++) { 998 if (strcasecmp(command, cmdp->name) == 0) { 999 state->where = cmdp->name; 1000 break; 1001 } 1002 } 1003 1004 if ((state->flags & PSC_STATE_FLAG_SMTPD_X21) 1005 && cmdp->action != psc_quit_cmd) { 1006 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event, 1007 state->final_reply); 1008 return; 1009 } 1010 /* Non-SMTP command test. */ 1011 if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_SKIP) 1012 == PSC_STATE_FLAG_NSMTP_TODO && cmdp->name == 0 1013 && (is_header(command) 1014 || PSC_BAD_UTF8(command) 1015 /* Ignore forbid_cmds lookup errors. Non-critical feature. */ 1016 || (*var_psc_forbid_cmds 1017 && string_list_match(psc_forbid_cmds, command)))) { 1018 printable(command, '?'); 1019 PSC_SMTPD_ESCAPE_TEXT(psc_temp, cmd_buffer_ptr, 1020 strlen(cmd_buffer_ptr), 100); 1021 msg_info("NON-SMTP COMMAND from [%s]:%s after %s: %.100s %s", 1022 PSC_CLIENT_ADDR_PORT(state), saved_where, 1023 command, STR(psc_temp)); 1024 PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_FAIL); 1025 PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_PASS); 1026 expire_time[PSC_TINDX_NSMTP] = PSC_TIME_STAMP_DISABLED; /* XXX */ 1027 /* Skip this test for the remainder of this SMTP session. */ 1028 PSC_SKIP_SESSION_STATE(state, "non-smtp test", 1029 PSC_STATE_FLAG_NSMTP_SKIP); 1030 switch (psc_nsmtp_action) { 1031 case PSC_ACT_DROP: 1032 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 1033 psc_smtpd_time_event, 1034 "521 5.7.0 Error: I can break rules, too. Goodbye.\r\n"); 1035 return; 1036 case PSC_ACT_ENFORCE: 1037 PSC_ENFORCE_SESSION_STATE(state, 1038 "550 5.5.1 Protocol error\r\n"); 1039 break; 1040 case PSC_ACT_IGNORE: 1041 PSC_UNFAIL_SESSION_STATE(state, 1042 PSC_STATE_FLAG_NSMTP_FAIL); 1043 /* Temporarily allowlist until something else expires. */ 1044 PSC_PASS_SESSION_STATE(state, "non-smtp test", 1045 PSC_STATE_FLAG_NSMTP_PASS); 1046 expire_time[PSC_TINDX_NSMTP] = event_time() + psc_min_ttl; 1047 break; 1048 default: 1049 msg_panic("%s: unknown non_smtp_command action value %d", 1050 myname, psc_nsmtp_action); 1051 } 1052 } 1053 /* Command PIPELINING test. */ 1054 if ((cmdp->flags & PSC_SMTPD_CMD_FLAG_HAS_PAYLOAD) == 0 1055 && (state->flags & PSC_STATE_MASK_PIPEL_TODO_SKIP) 1056 == PSC_STATE_FLAG_PIPEL_TODO && !PSC_SMTPD_BUFFER_EMPTY(state)) { 1057 printable(command, '?'); 1058 PSC_SMTPD_ESCAPE_TEXT(psc_temp, PSC_SMTPD_PEEK_DATA(state), 1059 PSC_SMTPD_PEEK_LEN(state), 100); 1060 msg_info("COMMAND PIPELINING from [%s]:%s after %.100s: %s", 1061 PSC_CLIENT_ADDR_PORT(state), command, STR(psc_temp)); 1062 PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_FAIL); 1063 PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_PASS); 1064 expire_time[PSC_TINDX_PIPEL] = PSC_TIME_STAMP_DISABLED; /* XXX */ 1065 /* Skip this test for the remainder of this SMTP session. */ 1066 PSC_SKIP_SESSION_STATE(state, "pipelining test", 1067 PSC_STATE_FLAG_PIPEL_SKIP); 1068 switch (psc_pipel_action) { 1069 case PSC_ACT_DROP: 1070 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, 1071 psc_smtpd_time_event, 1072 "521 5.5.1 Protocol error\r\n"); 1073 return; 1074 case PSC_ACT_ENFORCE: 1075 PSC_ENFORCE_SESSION_STATE(state, 1076 "550 5.5.1 Protocol error\r\n"); 1077 break; 1078 case PSC_ACT_IGNORE: 1079 PSC_UNFAIL_SESSION_STATE(state, 1080 PSC_STATE_FLAG_PIPEL_FAIL); 1081 /* Temporarily allowlist until something else expires. */ 1082 PSC_PASS_SESSION_STATE(state, "pipelining test", 1083 PSC_STATE_FLAG_PIPEL_PASS); 1084 expire_time[PSC_TINDX_PIPEL] = event_time() + psc_min_ttl; 1085 break; 1086 default: 1087 msg_panic("%s: unknown pipelining action value %d", 1088 myname, psc_pipel_action); 1089 } 1090 } 1091 1092 /* 1093 * The following tests don't pass until the client gets all the way 1094 * to the RCPT TO command. However, the client can still fail these 1095 * tests with some later command. 1096 */ 1097 if (cmdp->action == psc_rcpt_cmd) { 1098 if ((state->flags & PSC_STATE_MASK_BARLF_TODO_PASS_FAIL) 1099 == PSC_STATE_FLAG_BARLF_TODO) { 1100 PSC_PASS_SESSION_STATE(state, "bare newline test", 1101 PSC_STATE_FLAG_BARLF_PASS); 1102 /* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */ 1103 expire_time[PSC_TINDX_BARLF] = event_time() + var_psc_barlf_ttl; 1104 } 1105 if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL) 1106 == PSC_STATE_FLAG_NSMTP_TODO) { 1107 PSC_PASS_SESSION_STATE(state, "non-smtp test", 1108 PSC_STATE_FLAG_NSMTP_PASS); 1109 /* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */ 1110 expire_time[PSC_TINDX_NSMTP] = event_time() + var_psc_nsmtp_ttl; 1111 } 1112 if ((state->flags & PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL) 1113 == PSC_STATE_FLAG_PIPEL_TODO) { 1114 PSC_PASS_SESSION_STATE(state, "pipelining test", 1115 PSC_STATE_FLAG_PIPEL_PASS); 1116 /* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */ 1117 expire_time[PSC_TINDX_PIPEL] = event_time() + var_psc_pipel_ttl; 1118 } 1119 } 1120 /* Command COUNT limit test. */ 1121 if (++state->command_count > var_psc_cmd_count 1122 && cmdp->action != psc_quit_cmd) { 1123 msg_info("COMMAND COUNT LIMIT from [%s]:%s after %s", 1124 PSC_CLIENT_ADDR_PORT(state), saved_where); 1125 PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event, 1126 psc_smtpd_421_reply); 1127 return; 1128 } 1129 /* Finally, execute the command. */ 1130 if (cmdp->name == 0 || (cmdp->flags & PSC_SMTPD_CMD_FLAG_ENABLE) == 0) { 1131 write_stat = PSC_SEND_REPLY(state, 1132 "502 5.5.2 Error: command not recognized\r\n"); 1133 } else if (var_psc_enforce_tls 1134 && (state->flags & PSC_STATE_FLAG_USING_TLS) == 0 1135 && (cmdp->flags & PSC_SMTPD_CMD_FLAG_PRE_TLS) == 0) { 1136 write_stat = PSC_SEND_REPLY(state, 1137 "530 5.7.0 Must issue a STARTTLS command first\r\n"); 1138 } else { 1139 write_stat = cmdp->action(state, cmd_buffer_ptr); 1140 if (cmdp->flags & PSC_SMTPD_CMD_FLAG_DESTROY) 1141 return; 1142 } 1143 1144 /* 1145 * Terminate the session after a write error. 1146 */ 1147 if (write_stat < 0) { 1148 PSC_CLEAR_EVENT_HANGUP(state, psc_smtpd_time_event); 1149 return; 1150 } 1151 1152 /* 1153 * We're suspended, waiting for some external event to happen. 1154 * Hopefully, someone will call us back to process the remainder of 1155 * the pending input, otherwise we could hang. 1156 */ 1157 if (cmdp->flags & PSC_SMTPD_CMD_FLAG_SUSPEND) 1158 return; 1159 1160 /* 1161 * Reset the command read timeout before reading the next command. 1162 */ 1163 event_request_timer(psc_smtpd_time_event, (void *) state, 1164 PSC_EFF_CMD_TIME_LIMIT); 1165 1166 /* 1167 * Yield this pseudo thread when the VSTREAM buffer is empty. 1168 */ 1169 if (PSC_SMTPD_BUFFER_EMPTY(state)) 1170 return; 1171 } 1172 } 1173 1174 /* psc_smtpd_tests - per-session deep protocol test initialization */ 1175 1176 void psc_smtpd_tests(PSC_STATE *state) 1177 { 1178 static char *myname = "psc_smtpd_tests"; 1179 1180 /* 1181 * Report errors and progress in the context of this test. 1182 */ 1183 PSC_BEGIN_TESTS(state, "tests after SMTP handshake"); 1184 1185 /* 1186 * Initialize per-session state that is used only by the dummy engine: 1187 * the command read buffer and the command read state machine. 1188 */ 1189 state->cmd_buffer = vstring_alloc(100); 1190 state->read_state = PSC_SMTPD_CMD_ST_ANY; 1191 1192 /* 1193 * Disable all after-220 tests when we need to reply with 421 and hang up 1194 * after reading the next SMTP client command. 1195 * 1196 * Opportunistically make postscreen more useful, by turning on all 1197 * after-220 tests when a bad client failed a before-220 test. 1198 * 1199 * Otherwise, only apply the explicitly-configured after-220 tests. 1200 */ 1201 if (state->flags & PSC_STATE_FLAG_SMTPD_X21) { 1202 state->flags &= ~PSC_STATE_MASK_SMTPD_TODO; 1203 } else if (state->flags & PSC_STATE_MASK_ANY_FAIL) { 1204 state->flags |= PSC_STATE_MASK_SMTPD_TODO; 1205 } 1206 1207 /* 1208 * Send no SMTP banner to pregreeting clients. This eliminates a lot of 1209 * "NON-SMTP COMMAND" events, and improves sender/recipient logging. 1210 */ 1211 if ((state->flags & PSC_STATE_FLAG_PREGR_FAIL) == 0 1212 && PSC_SEND_REPLY(state, psc_smtpd_greeting) != 0) { 1213 psc_hangup_event(state); 1214 return; 1215 } 1216 1217 /* 1218 * Wait for the client to respond. 1219 */ 1220 PSC_READ_EVENT_REQUEST2(vstream_fileno(state->smtp_client_stream), 1221 psc_smtpd_read_event, psc_smtpd_time_event, 1222 (void *) state, PSC_EFF_CMD_TIME_LIMIT); 1223 } 1224 1225 /* psc_smtpd_init - per-process deep protocol test initialization */ 1226 1227 void psc_smtpd_init(void) 1228 { 1229 1230 /* 1231 * Initialize the server banner. 1232 */ 1233 vstring_sprintf(psc_temp, "220 %s\r\n", var_smtpd_banner); 1234 psc_smtpd_greeting = mystrdup(STR(psc_temp)); 1235 1236 /* 1237 * Initialize the HELO reply. 1238 */ 1239 vstring_sprintf(psc_temp, "250 %s\r\n", var_myhostname); 1240 psc_smtpd_helo_reply = mystrdup(STR(psc_temp)); 1241 1242 /* 1243 * STARTTLS support. Note the complete absence of #ifdef USE_TLS 1244 * throughout the postscreen(8) source code. If Postfix is built without 1245 * TLS support, then the TLS proxy will simply report that TLS is not 1246 * available, and conventional error handling will take care of the 1247 * issue. 1248 * 1249 * Legacy code copied from smtpd(8). The pre-fabricated EHLO reply depends 1250 * on this. 1251 */ 1252 if (*var_psc_tls_level) { 1253 switch (tls_level_lookup(var_psc_tls_level)) { 1254 default: 1255 msg_fatal("Invalid TLS level \"%s\"", var_psc_tls_level); 1256 /* NOTREACHED */ 1257 break; 1258 case TLS_LEV_SECURE: 1259 case TLS_LEV_VERIFY: 1260 case TLS_LEV_FPRINT: 1261 msg_warn("%s: unsupported TLS level \"%s\", using \"encrypt\"", 1262 VAR_PSC_TLS_LEVEL, var_psc_tls_level); 1263 /* FALLTHROUGH */ 1264 case TLS_LEV_ENCRYPT: 1265 var_psc_enforce_tls = var_psc_use_tls = 1; 1266 break; 1267 case TLS_LEV_MAY: 1268 var_psc_enforce_tls = 0; 1269 var_psc_use_tls = 1; 1270 break; 1271 case TLS_LEV_NONE: 1272 var_psc_enforce_tls = var_psc_use_tls = 0; 1273 break; 1274 } 1275 } 1276 var_psc_use_tls = var_psc_use_tls || var_psc_enforce_tls; 1277 #ifdef TODO_SASL_AUTH 1278 var_psc_tls_auth_only = var_psc_tls_auth_only || var_psc_enforce_tls; 1279 #endif 1280 1281 /* 1282 * Initialize the EHLO reply. Once for plaintext sessions, and once for 1283 * TLS sessions. 1284 */ 1285 psc_smtpd_format_ehlo_reply(psc_temp, psc_ehlo_discard_mask); 1286 psc_smtpd_ehlo_reply_plain = mystrdup(STR(psc_temp)); 1287 1288 psc_smtpd_format_ehlo_reply(psc_temp, 1289 psc_ehlo_discard_mask | EHLO_MASK_STARTTLS); 1290 psc_smtpd_ehlo_reply_tls = mystrdup(STR(psc_temp)); 1291 1292 /* 1293 * Initialize the 421 timeout reply. 1294 */ 1295 vstring_sprintf(psc_temp, "421 4.4.2 %s Error: timeout exceeded\r\n", 1296 var_myhostname); 1297 psc_smtpd_timeout_reply = mystrdup(STR(psc_temp)); 1298 1299 /* 1300 * Initialize the generic 421 reply. 1301 */ 1302 vstring_sprintf(psc_temp, "421 %s Service unavailable - try again later\r\n", 1303 var_myhostname); 1304 psc_smtpd_421_reply = mystrdup(STR(psc_temp)); 1305 1306 /* 1307 * Initialize the reply footer. 1308 */ 1309 if (*var_psc_rej_footer || *var_psc_rej_ftr_maps) 1310 psc_expand_init(); 1311 } 1312 1313 /* psc_smtpd_pre_jail_init - per-process deep protocol test initialization */ 1314 1315 void psc_smtpd_pre_jail_init(void) 1316 { 1317 1318 /* 1319 * Determine what server ESMTP features to suppress, typically to avoid 1320 * inter-operability problems. We do the default filter here, and 1321 * determine client-dependent filtering on the fly. 1322 * 1323 * XXX Bugger. This means we have to restart when the table changes! 1324 */ 1325 if (*var_psc_ehlo_dis_maps) 1326 psc_ehlo_discard_maps = maps_create(VAR_PSC_EHLO_DIS_MAPS, 1327 var_psc_ehlo_dis_maps, 1328 DICT_FLAG_LOCK); 1329 psc_ehlo_discard_mask = ehlo_mask(var_psc_ehlo_dis_words); 1330 1331 /* 1332 * Last-resort command editing support. 1333 */ 1334 if (*var_psc_cmd_filter) 1335 psc_cmd_filter = dict_open(var_psc_cmd_filter, O_RDONLY, 1336 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX); 1337 1338 /* 1339 * SMTP server reply footer. 1340 */ 1341 if (*var_psc_rej_ftr_maps) 1342 pcs_send_pre_jail_init(); 1343 } 1344