1 /* $NetBSD: verify.c,v 1.6 2026/05/09 18:49:23 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* verify 8 6 /* SUMMARY 7 /* Postfix address verification server 8 /* SYNOPSIS 9 /* \fBverify\fR [generic Postfix daemon options] 10 /* DESCRIPTION 11 /* The \fBverify\fR(8) address verification server maintains a record 12 /* of what recipient addresses are known to be deliverable or 13 /* undeliverable. 14 /* 15 /* Addresses are verified by injecting probe messages into the 16 /* Postfix queue. Probe messages are run through all the routing 17 /* and rewriting machinery except for final delivery, and are 18 /* discarded rather than being deferred or bounced. 19 /* 20 /* Address verification relies on the answer from the nearest 21 /* MTA for the specified address, and will therefore not detect 22 /* all undeliverable addresses. 23 /* 24 /* The \fBverify\fR(8) server is designed to run under control 25 /* by the Postfix 26 /* master server. It maintains an optional persistent database. 27 /* To avoid being interrupted by "postfix stop" in the middle 28 /* of a database update, the process runs in a separate process 29 /* group. 30 /* 31 /* The \fBverify\fR(8) server implements the following requests: 32 /* .IP "\fBupdate\fI address status text\fR" 33 /* Update the status and text of the specified address. 34 /* .IP "\fBquery\fI address\fR" 35 /* Look up the \fIstatus\fR and \fItext\fR for the specified 36 /* \fIaddress\fR. 37 /* If the status is unknown, a probe is sent and an "in progress" 38 /* status is returned. 39 /* SECURITY 40 /* .ad 41 /* .fi 42 /* The address verification server is not security-sensitive. It does 43 /* not talk to the network, and it does not talk to local users. 44 /* The verify server can run chrooted at fixed low privilege. 45 /* 46 /* The address verification server can be coerced to store 47 /* unlimited amounts of garbage. Limiting the cache expiry 48 /* time 49 /* trades one problem (disk space exhaustion) for another 50 /* one (poor response time to client requests). 51 /* 52 /* With Postfix version 2.5 and later, the \fBverify\fR(8) 53 /* server no longer uses root privileges when opening the 54 /* \fBaddress_verify_map\fR cache file. The file should now 55 /* be stored under the Postfix-owned \fBdata_directory\fR. As 56 /* a migration aid, an attempt to open a cache file under a 57 /* non-Postfix directory is redirected to the Postfix-owned 58 /* \fBdata_directory\fR, and a warning is logged. 59 /* DIAGNOSTICS 60 /* Problems and transactions are logged to \fBsyslogd\fR(8) 61 /* or \fBpostlogd\fR(8). 62 /* BUGS 63 /* Address verification probe messages add additional traffic 64 /* to the mail queue. 65 /* Recipient verification may cause an increased load on 66 /* down-stream servers in the case of a dictionary attack or 67 /* a flood of backscatter bounces. 68 /* Sender address verification may cause your site to be 69 /* denylisted by some providers. 70 /* 71 /* If the persistent database ever gets corrupted then the world 72 /* comes to an end and human intervention is needed. This violates 73 /* a basic Postfix principle. 74 /* CONFIGURATION PARAMETERS 75 /* .ad 76 /* .fi 77 /* Changes to \fBmain.cf\fR are not picked up automatically, 78 /* as \fBverify\fR(8) 79 /* processes are long-lived. Use the command "\fBpostfix reload\fR" after 80 /* a configuration change. 81 /* 82 /* The text below provides only a parameter summary. See 83 /* \fBpostconf\fR(5) for more details including examples. 84 /* PROBE MESSAGE CONTROLS 85 /* .ad 86 /* .fi 87 /* .IP "\fBaddress_verify_sender ($double_bounce_sender)\fR" 88 /* The sender address to use in address verification probes; prior 89 /* to Postfix 2.5 the default was "postmaster". 90 /* .PP 91 /* Available with Postfix 2.9 and later: 92 /* .IP "\fBaddress_verify_sender_ttl (0s)\fR" 93 /* The time between changes in the time-dependent portion of address 94 /* verification probe sender addresses. 95 /* CACHE CONTROLS 96 /* .ad 97 /* .fi 98 /* .IP "\fBaddress_verify_map (see 'postconf -d' output)\fR" 99 /* Lookup table for persistent address verification status 100 /* storage. 101 /* .IP "\fBaddress_verify_positive_expire_time (31d)\fR" 102 /* The time after which a successful probe expires from the address 103 /* verification cache. 104 /* .IP "\fBaddress_verify_positive_refresh_time (7d)\fR" 105 /* The time after which a successful address verification probe needs 106 /* to be refreshed. 107 /* .IP "\fBaddress_verify_negative_cache (yes)\fR" 108 /* Enable caching of failed address verification probe results. 109 /* .IP "\fBaddress_verify_negative_expire_time (3d)\fR" 110 /* The time after which a failed probe expires from the address 111 /* verification cache. 112 /* .IP "\fBaddress_verify_negative_refresh_time (3h)\fR" 113 /* The time after which a failed address verification probe needs to 114 /* be refreshed. 115 /* .PP 116 /* Available with Postfix 2.7 and later: 117 /* .IP "\fBaddress_verify_cache_cleanup_interval (12h)\fR" 118 /* The amount of time between \fBverify\fR(8) address verification 119 /* database cleanup runs. 120 /* PROBE MESSAGE ROUTING CONTROLS 121 /* .ad 122 /* .fi 123 /* By default, probe messages are delivered via the same route 124 /* as regular messages. The following parameters can be used to 125 /* override specific message routing mechanisms. 126 /* .IP "\fBaddress_verify_relayhost ($relayhost)\fR" 127 /* Overrides the relayhost parameter setting for address verification 128 /* probes. 129 /* .IP "\fBaddress_verify_transport_maps ($transport_maps)\fR" 130 /* Overrides the transport_maps parameter setting for address verification 131 /* probes. 132 /* .IP "\fBaddress_verify_local_transport ($local_transport)\fR" 133 /* Overrides the local_transport parameter setting for address 134 /* verification probes. 135 /* .IP "\fBaddress_verify_virtual_transport ($virtual_transport)\fR" 136 /* Overrides the virtual_transport parameter setting for address 137 /* verification probes. 138 /* .IP "\fBaddress_verify_relay_transport ($relay_transport)\fR" 139 /* Overrides the relay_transport parameter setting for address 140 /* verification probes. 141 /* .IP "\fBaddress_verify_default_transport ($default_transport)\fR" 142 /* Overrides the default_transport parameter setting for address 143 /* verification probes. 144 /* .PP 145 /* Available in Postfix 2.3 and later: 146 /* .IP "\fBaddress_verify_sender_dependent_relayhost_maps ($sender_dependent_relayhost_maps)\fR" 147 /* Overrides the sender_dependent_relayhost_maps parameter setting for address 148 /* verification probes. 149 /* .PP 150 /* Available in Postfix 2.7 and later: 151 /* .IP "\fBaddress_verify_sender_dependent_default_transport_maps ($sender_dependent_default_transport_maps)\fR" 152 /* Overrides the sender_dependent_default_transport_maps parameter 153 /* setting for address verification probes. 154 /* SMTPUTF8 CONTROLS 155 /* .ad 156 /* .fi 157 /* Preliminary SMTPUTF8 support is introduced with Postfix 3.0. 158 /* .IP "\fBsmtputf8_autodetect_classes (sendmail, verify)\fR" 159 /* Detect that a message requires SMTPUTF8 support for the specified 160 /* mail origin classes. 161 /* .PP 162 /* Available in Postfix version 3.2 and later: 163 /* .IP "\fBenable_idna2003_compatibility (no)\fR" 164 /* Enable 'transitional' compatibility between IDNA2003 and IDNA2008, 165 /* when converting UTF-8 domain names to/from the ASCII form that is 166 /* used for DNS lookups. 167 /* MISCELLANEOUS CONTROLS 168 /* .ad 169 /* .fi 170 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR" 171 /* The default location of the Postfix main.cf and master.cf 172 /* configuration files. 173 /* .IP "\fBdaemon_timeout (18000s)\fR" 174 /* How much time a Postfix daemon process may take to handle a 175 /* request before it is terminated by a built-in watchdog timer. 176 /* .IP "\fBipc_timeout (3600s)\fR" 177 /* The time limit for sending or receiving information over an internal 178 /* communication channel. 179 /* .IP "\fBprocess_id (read-only)\fR" 180 /* The process ID of a Postfix command or daemon process. 181 /* .IP "\fBprocess_name (read-only)\fR" 182 /* The process name of a Postfix command or daemon process. 183 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR" 184 /* The location of the Postfix top-level queue directory. 185 /* .IP "\fBsyslog_facility (mail)\fR" 186 /* The syslog facility of Postfix logging. 187 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR" 188 /* A prefix that is prepended to the process name in syslog 189 /* records, so that, for example, "smtpd" becomes "prefix/smtpd". 190 /* .PP 191 /* Available in Postfix 3.3 and later: 192 /* .IP "\fBservice_name (read-only)\fR" 193 /* The master.cf service name of a Postfix daemon process. 194 /* SEE ALSO 195 /* smtpd(8), Postfix SMTP server 196 /* cleanup(8), enqueue Postfix message 197 /* postconf(5), configuration parameters 198 /* postlogd(8), Postfix logging 199 /* syslogd(8), system logging 200 /* README FILES 201 /* .ad 202 /* .fi 203 /* Use "\fBpostconf readme_directory\fR" or 204 /* "\fBpostconf html_directory\fR" to locate this information. 205 /* .na 206 /* .nf 207 /* ADDRESS_VERIFICATION_README, address verification howto 208 /* LICENSE 209 /* .ad 210 /* .fi 211 /* The Secure Mailer license must be distributed with this software. 212 /* HISTORY 213 /* .ad 214 /* .fi 215 /* This service was introduced with Postfix version 2.1. 216 /* AUTHOR(S) 217 /* Wietse Venema 218 /* IBM T.J. Watson Research 219 /* P.O. Box 704 220 /* Yorktown Heights, NY 10598, USA 221 /* 222 /* Wietse Venema 223 /* Google, Inc. 224 /* 111 8th Avenue 225 /* New York, NY 10011, USA 226 /*--*/ 227 228 /* System library. */ 229 230 #include <sys_defs.h> 231 #include <sys/stat.h> 232 #include <time.h> 233 #include <string.h> 234 #include <stdlib.h> 235 #include <unistd.h> 236 237 /* Utility library. */ 238 239 #include <msg.h> 240 #include <mymalloc.h> 241 #include <htable.h> 242 #include <dict_ht.h> 243 #include <dict_cache.h> 244 #include <split_at.h> 245 #include <stringops.h> 246 #include <set_eugid.h> 247 #include <events.h> 248 249 /* Global library. */ 250 251 #include <mail_conf.h> 252 #include <mail_params.h> 253 #include <mail_version.h> 254 #include <mail_proto.h> 255 #include <post_mail.h> 256 #include <data_redirect.h> 257 #include <verify_clnt.h> 258 #include <verify_sender_addr.h> 259 260 /* Server skeleton. */ 261 262 #include <mail_server.h> 263 264 /* Application-specific. */ 265 266 /* 267 * Tunable parameters. 268 */ 269 char *var_verify_map; 270 int var_verify_pos_exp; 271 int var_verify_pos_try; 272 int var_verify_neg_exp; 273 int var_verify_neg_try; 274 int var_verify_scan_cache; 275 276 /* 277 * State. 278 */ 279 static DICT_CACHE *verify_map; 280 281 /* 282 * Silly little macros. 283 */ 284 #define STR(x) vstring_str(x) 285 #define STREQ(x,y) (strcmp(x,y) == 0) 286 287 /* 288 * The address verification database consists of (address, data) tuples. The 289 * format of the data field is "status:probed:updated:text". The meaning of 290 * each field is: 291 * 292 * status: one of the four recipient status codes (OK, DEFER, BOUNCE or TODO). 293 * In the case of TODO, we have no information about the address, and the 294 * address is being probed. 295 * 296 * probed: if non-zero, the time the currently outstanding address probe was 297 * sent. If zero, there is no outstanding address probe. 298 * 299 * updated: if non-zero, the time the address probe result was received. If 300 * zero, we have no information about the address, and the address is being 301 * probed. 302 * 303 * text: descriptive text from delivery agents etc. 304 */ 305 306 /* 307 * Quick test to see status without parsing the whole entry. 308 */ 309 #define STATUS_FROM_RAW_ENTRY(e) atoi(e) 310 311 /* verify_make_entry - construct table entry */ 312 313 static void verify_make_entry(VSTRING *buf, int status, long probed, 314 long updated, const char *text) 315 { 316 vstring_sprintf(buf, "%d:%ld:%ld:%s", status, probed, updated, text); 317 } 318 319 /* verify_parse_entry - parse table entry */ 320 321 static int verify_parse_entry(char *buf, int *status, long *probed, 322 long *updated, char **text) 323 { 324 char *probed_text; 325 char *updated_text; 326 327 if ((probed_text = split_at(buf, ':')) != 0 328 && (updated_text = split_at(probed_text, ':')) != 0 329 && (*text = split_at(updated_text, ':')) != 0 330 && alldig(buf) 331 && alldig(probed_text) 332 && alldig(updated_text)) { 333 *probed = atol(probed_text); 334 *updated = atol(updated_text); 335 *status = atoi(buf); 336 337 /* 338 * Coverity 200604: the code incorrectly tested (probed || updated), 339 * so that the sanity check never detected all-zero time stamps. Such 340 * records are never written. If we read a record with all-zero time 341 * stamps, then something is badly broken. 342 */ 343 if ((*status == DEL_RCPT_STAT_OK 344 || *status == DEL_RCPT_STAT_DEFER 345 || *status == DEL_RCPT_STAT_BOUNCE 346 || *status == DEL_RCPT_STAT_TODO) 347 && (*probed || *updated)) 348 return (0); 349 } 350 msg_warn("bad address verify table entry: %.100s", buf); 351 return (-1); 352 } 353 354 /* verify_stat2name - status to name */ 355 356 static const char *verify_stat2name(int addr_status) 357 { 358 if (addr_status == DEL_RCPT_STAT_OK) 359 return ("deliverable"); 360 if (addr_status == DEL_RCPT_STAT_DEFER) 361 return ("undeliverable"); 362 if (addr_status == DEL_RCPT_STAT_BOUNCE) 363 return ("undeliverable"); 364 return (0); 365 } 366 367 /* verify_update_service - update address service */ 368 369 static void verify_update_service(VSTREAM *client_stream) 370 { 371 VSTRING *buf = vstring_alloc(10); 372 VSTRING *addr = vstring_alloc(10); 373 int addr_status; 374 VSTRING *text = vstring_alloc(10); 375 const char *status_name; 376 const char *raw_data; 377 long probed; 378 long updated; 379 380 if (attr_scan(client_stream, ATTR_FLAG_STRICT, 381 RECV_ATTR_STR(MAIL_ATTR_ADDR, addr), 382 RECV_ATTR_INT(MAIL_ATTR_ADDR_STATUS, &addr_status), 383 RECV_ATTR_STR(MAIL_ATTR_WHY, text), 384 ATTR_TYPE_END) == 3) { 385 /* FIX 200501 IPv6 patch did not neuter ":" in address literals. */ 386 translit(STR(addr), ":", "_"); 387 if ((status_name = verify_stat2name(addr_status)) == 0) { 388 msg_warn("bad recipient status %d for recipient %s", 389 addr_status, STR(addr)); 390 attr_print(client_stream, ATTR_FLAG_NONE, 391 SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_BAD), 392 ATTR_TYPE_END); 393 } else { 394 395 /* 396 * Robustness: don't allow a failed probe to clobber an OK 397 * address before it expires. The failed probe is ignored so that 398 * the address will be re-probed upon the next query. As long as 399 * some probes succeed the address will remain cached as OK. 400 */ 401 if (addr_status == DEL_RCPT_STAT_OK 402 || (raw_data = dict_cache_lookup(verify_map, STR(addr))) == 0 403 || STATUS_FROM_RAW_ENTRY(raw_data) != DEL_RCPT_STAT_OK) { 404 probed = 0; 405 updated = (long) time((time_t *) 0); 406 printable(STR(text), '?'); 407 verify_make_entry(buf, addr_status, probed, updated, STR(text)); 408 if (msg_verbose) 409 msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s", 410 STR(addr), addr_status, probed, updated, STR(text)); 411 dict_cache_update(verify_map, STR(addr), STR(buf)); 412 } 413 attr_print(client_stream, ATTR_FLAG_NONE, 414 SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_OK), 415 ATTR_TYPE_END); 416 } 417 } 418 vstring_free(buf); 419 vstring_free(addr); 420 vstring_free(text); 421 } 422 423 /* verify_post_mail_fclose_action - callback */ 424 425 static void verify_post_mail_fclose_action(int unused_status, 426 void *unused_context) 427 { 428 /* no code here, we just need to avoid blocking in post_mail_fclose() */ 429 } 430 431 /* verify_post_mail_action - callback */ 432 433 static void verify_post_mail_action(VSTREAM *stream, void *context) 434 { 435 436 /* 437 * Probe messages need no body content, because they are never delivered, 438 * deferred, or bounced. 439 */ 440 if (stream != 0) 441 post_mail_fclose_async(stream, verify_post_mail_fclose_action, context); 442 } 443 444 /* verify_query_service - query address status */ 445 446 static void verify_query_service(VSTREAM *client_stream) 447 { 448 VSTRING *addr = vstring_alloc(10); 449 VSTRING *get_buf = 0; 450 VSTRING *put_buf = 0; 451 const char *raw_data; 452 int addr_status; 453 long probed; 454 long updated; 455 char *text; 456 457 if (attr_scan(client_stream, ATTR_FLAG_STRICT, 458 RECV_ATTR_STR(MAIL_ATTR_ADDR, addr), 459 ATTR_TYPE_END) == 1) { 460 long now = (long) time((time_t *) 0); 461 462 /* 463 * Produce a default record when no usable record exists. 464 * 465 * If negative caching is disabled, purge an expired record from the 466 * database. 467 * 468 * XXX Assume that a probe is lost if no response is received in 1000 469 * seconds. If this number is too small the queue will slowly fill up 470 * with delayed probes. 471 * 472 * XXX Maintain a moving average for the probe turnaround time, and 473 * allow probe "retransmission" when a probe is outstanding for, say 474 * some minimal amount of time (1000 sec) plus several times the 475 * observed probe turnaround time. This causes probing to back off 476 * when the mail system becomes congested. 477 */ 478 #define POSITIVE_ENTRY_EXPIRED(addr_status, updated) \ 479 (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_exp < now) 480 #define NEGATIVE_ENTRY_EXPIRED(addr_status, updated) \ 481 (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_exp < now) 482 #define PROBE_TTL 1000 483 484 /* FIX 200501 IPv6 patch did not neuter ":" in address literals. */ 485 translit(STR(addr), ":", "_"); 486 raw_data = dict_cache_lookup(verify_map, STR(addr)); 487 if (dict_cache_error(verify_map) != 0) { 488 addr_status = DEL_RCPT_STAT_DEFER; 489 probed = 0; 490 updated = 0; 491 text = "Address verification status unavailable"; 492 } else if (raw_data == 0 /* not found */ 493 || ((get_buf = vstring_alloc(10)), 494 vstring_strcpy(get_buf, raw_data), /* malformed */ 495 verify_parse_entry(STR(get_buf), &addr_status, &probed, 496 &updated, &text) < 0) 497 || (now - probed > PROBE_TTL /* safe to probe */ 498 && (POSITIVE_ENTRY_EXPIRED(addr_status, updated) 499 || NEGATIVE_ENTRY_EXPIRED(addr_status, updated)))) { 500 addr_status = DEL_RCPT_STAT_TODO; 501 probed = 0; 502 updated = 0; 503 text = "Address verification in progress"; 504 if (raw_data != 0 && var_verify_neg_cache == 0) 505 dict_cache_delete(verify_map, STR(addr)); 506 } 507 if (msg_verbose) 508 msg_info("GOT %s status=%d probed=%ld updated=%ld text=%s", 509 STR(addr), addr_status, probed, updated, text); 510 511 /* 512 * Respond to the client. 513 */ 514 attr_print(client_stream, ATTR_FLAG_NONE, 515 SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_OK), 516 SEND_ATTR_INT(MAIL_ATTR_ADDR_STATUS, addr_status), 517 SEND_ATTR_STR(MAIL_ATTR_WHY, text), 518 ATTR_TYPE_END); 519 520 /* 521 * Send a new probe when the information needs to be refreshed. 522 * 523 * XXX For an initial proof of concept implementation, use synchronous 524 * mail submission. This needs to be made async for high-volume 525 * sites, which makes it even more interesting to eliminate duplicate 526 * queries while a probe is being built. 527 * 528 * If negative caching is turned off, update the database only when 529 * refreshing an existing entry. 530 */ 531 #define POSITIVE_REFRESH_NEEDED(addr_status, updated) \ 532 (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_try < now) 533 #define NEGATIVE_REFRESH_NEEDED(addr_status, updated) \ 534 (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_try < now) 535 536 if (dict_cache_error(verify_map) == 0 && now - probed > PROBE_TTL 537 && (POSITIVE_REFRESH_NEEDED(addr_status, updated) 538 || NEGATIVE_REFRESH_NEEDED(addr_status, updated))) { 539 if (msg_verbose) 540 msg_info("PROBE %s status=%d probed=%ld updated=%ld", 541 STR(addr), addr_status, now, updated); 542 post_mail_fopen_async(make_verify_sender_addr(), STR(addr), 543 MAIL_SRC_MASK_VERIFY, 544 DEL_REQ_FLAG_MTA_VRFY, 545 /* TODO(wietse) disable REQUIRETLS? */ 546 SMTPUTF8_FLAG_NONE, 547 (VSTRING *) 0, 548 verify_post_mail_action, 549 (void *) 0); 550 if (updated != 0 || var_verify_neg_cache != 0) { 551 put_buf = vstring_alloc(10); 552 verify_make_entry(put_buf, addr_status, now, updated, text); 553 if (msg_verbose) 554 msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s", 555 STR(addr), addr_status, now, updated, text); 556 dict_cache_update(verify_map, STR(addr), STR(put_buf)); 557 } 558 } 559 } 560 vstring_free(addr); 561 if (get_buf) 562 vstring_free(get_buf); 563 if (put_buf) 564 vstring_free(put_buf); 565 } 566 567 /* verify_cache_validator - cache cleanup validator */ 568 569 static int verify_cache_validator(const char *addr, const char *raw_data, 570 void *context) 571 { 572 VSTRING *get_buf = (VSTRING *) context; 573 int addr_status; 574 long probed; 575 long updated; 576 char *text; 577 long now = (long) event_time(); 578 579 #define POS_OR_NEG_ENTRY_EXPIRED(stat, stamp) \ 580 (POSITIVE_ENTRY_EXPIRED((stat), (stamp)) \ 581 || NEGATIVE_ENTRY_EXPIRED((stat), (stamp))) 582 583 vstring_strcpy(get_buf, raw_data); 584 return (verify_parse_entry(STR(get_buf), &addr_status, /* syntax OK */ 585 &probed, &updated, &text) == 0 586 && (now - probed < PROBE_TTL /* probe in progress */ 587 || !POS_OR_NEG_ENTRY_EXPIRED(addr_status, updated))); 588 } 589 590 /* verify_service - perform service for client */ 591 592 static void verify_service(VSTREAM *client_stream, char *unused_service, 593 char **argv) 594 { 595 VSTRING *request = vstring_alloc(10); 596 597 /* 598 * Sanity check. This service takes no command-line arguments. 599 */ 600 if (argv[0]) 601 msg_fatal("unexpected command-line argument: %s", argv[0]); 602 603 /* 604 * This routine runs whenever a client connects to the socket dedicated 605 * to the address verification service. All connection-management stuff 606 * is handled by the common code in multi_server.c. 607 */ 608 if (attr_scan(client_stream, 609 ATTR_FLAG_MORE | ATTR_FLAG_STRICT, 610 RECV_ATTR_STR(MAIL_ATTR_REQ, request), 611 ATTR_TYPE_END) == 1) { 612 if (STREQ(STR(request), VRFY_REQ_UPDATE)) { 613 verify_update_service(client_stream); 614 } else if (STREQ(STR(request), VRFY_REQ_QUERY)) { 615 verify_query_service(client_stream); 616 } else { 617 msg_warn("unrecognized request: \"%s\", ignored", STR(request)); 618 attr_print(client_stream, ATTR_FLAG_NONE, 619 SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_BAD), 620 ATTR_TYPE_END); 621 } 622 } 623 vstream_fflush(client_stream); 624 vstring_free(request); 625 } 626 627 /* verify_dump - dump some statistics */ 628 629 static void verify_dump(char *unused_name, char **unused_argv) 630 { 631 632 /* 633 * Dump preliminary cache cleanup statistics when the process commits 634 * suicide while a cache cleanup run is in progress. We can't currently 635 * distinguish between "postfix reload" (we should restart) or "maximal 636 * idle time reached" (we could finish the cache cleanup first). 637 */ 638 dict_cache_close(verify_map); 639 verify_map = 0; 640 } 641 642 /* post_jail_init - post-jail initialization */ 643 644 static void post_jail_init(char *unused_name, char **unused_argv) 645 { 646 647 /* 648 * If the database is in volatile memory only, prevent automatic process 649 * suicide after a limited number of client requests or after a limited 650 * amount of idle time. 651 */ 652 if (*var_verify_map == 0) { 653 var_use_limit = 0; 654 var_idle_limit = 0; 655 } 656 657 /* 658 * Start the cache cleanup thread. 659 */ 660 if (var_verify_scan_cache > 0) { 661 int cache_flags; 662 663 cache_flags = DICT_CACHE_FLAG_STATISTICS; 664 if (msg_verbose) 665 cache_flags |= DICT_CACHE_FLAG_VERBOSE; 666 dict_cache_control(verify_map, 667 CA_DICT_CACHE_CTL_FLAGS(cache_flags), 668 CA_DICT_CACHE_CTL_INTERVAL(var_verify_scan_cache), 669 CA_DICT_CACHE_CTL_VALIDATOR(verify_cache_validator), 670 CA_DICT_CACHE_CTL_CONTEXT((void *) vstring_alloc(100)), 671 CA_DICT_CACHE_CTL_END); 672 } 673 } 674 675 /* pre_jail_init - pre-jail initialization */ 676 677 static void pre_jail_init(char *unused_name, char **unused_argv) 678 { 679 mode_t saved_mask; 680 VSTRING *redirect; 681 682 /* 683 * Never, ever, get killed by a master signal, as that would corrupt the 684 * database when we're in the middle of an update. 685 */ 686 setsid(); 687 688 /* 689 * Security: don't create root-owned files that contain untrusted data. 690 * And don't create Postfix-owned files in root-owned directories, 691 * either. We want a correct relationship between (file/directory) 692 * ownership and (file/directory) content. 693 * 694 * XXX Non-root open can violate the principle of least surprise: Postfix 695 * can't open an *SQL config file for database read-write access, even 696 * though it can open that same control file for database read-only 697 * access. 698 * 699 * The solution is to query a map type and obtain its properties before 700 * opening it. A clean solution is to add a dict_info() API that is 701 * similar to dict_open() except it returns properties (dict flags) only. 702 * A pragmatic solution is to overload the existing API and have 703 * dict_open() return a dummy map when given a null map name. 704 * 705 * However, the proxymap daemon has been opening *SQL maps as non-root for 706 * years now without anyone complaining, let's not solve a problem that 707 * doesn't exist. 708 */ 709 SAVE_AND_SET_EUGID(var_owner_uid, var_owner_gid); 710 redirect = vstring_alloc(100); 711 712 /* 713 * Keep state in persistent (external) or volatile (internal) map. 714 * 715 * Start the cache cleanup thread after permanently dropping privileges. 716 */ 717 #define VERIFY_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE \ 718 | DICT_FLAG_OPEN_LOCK | DICT_FLAG_UTF8_REQUEST) 719 720 saved_mask = umask(022); 721 verify_map = 722 dict_cache_open(*var_verify_map ? 723 data_redirect_map(redirect, var_verify_map) : 724 "internal:verify", 725 O_CREAT | O_RDWR, VERIFY_DICT_OPEN_FLAGS); 726 (void) umask(saved_mask); 727 728 /* 729 * Clean up and restore privilege. 730 */ 731 vstring_free(redirect); 732 RESTORE_SAVED_EUGID(); 733 } 734 735 /* post_accept_init - announce our protocol */ 736 737 static void post_accept_init(VSTREAM *stream, char *unused_name, 738 char **unused_argv, HTABLE *unused_table) 739 { 740 741 /* 742 * Announce the protocol. 743 */ 744 attr_print(stream, ATTR_FLAG_NONE, 745 SEND_ATTR_STR(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_VERIFY), 746 ATTR_TYPE_END); 747 (void) vstream_fflush(stream); 748 } 749 750 MAIL_VERSION_STAMP_DECLARE; 751 752 /* main - pass control to the multi-threaded skeleton */ 753 754 int main(int argc, char **argv) 755 { 756 static const CONFIG_STR_TABLE str_table[] = { 757 VAR_VERIFY_MAP, DEF_VERIFY_MAP, &var_verify_map, 0, 0, 758 VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0, 759 0, 760 }; 761 static const CONFIG_TIME_TABLE time_table[] = { 762 VAR_VERIFY_POS_EXP, DEF_VERIFY_POS_EXP, &var_verify_pos_exp, 1, 0, 763 VAR_VERIFY_POS_TRY, DEF_VERIFY_POS_TRY, &var_verify_pos_try, 1, 0, 764 VAR_VERIFY_NEG_EXP, DEF_VERIFY_NEG_EXP, &var_verify_neg_exp, 1, 0, 765 VAR_VERIFY_NEG_TRY, DEF_VERIFY_NEG_TRY, &var_verify_neg_try, 1, 0, 766 VAR_VERIFY_SCAN_CACHE, DEF_VERIFY_SCAN_CACHE, &var_verify_scan_cache, 0, 0, 767 VAR_VERIFY_SENDER_TTL, DEF_VERIFY_SENDER_TTL, &var_verify_sender_ttl, 0, 0, 768 0, 769 }; 770 771 /* 772 * Fingerprint executables and core dumps. 773 */ 774 MAIL_VERSION_STAMP_ALLOCATE; 775 776 multi_server_main(argc, argv, verify_service, 777 CA_MAIL_SERVER_STR_TABLE(str_table), 778 CA_MAIL_SERVER_TIME_TABLE(time_table), 779 CA_MAIL_SERVER_PRE_INIT(pre_jail_init), 780 CA_MAIL_SERVER_POST_INIT(post_jail_init), 781 CA_MAIL_SERVER_POST_ACCEPT(post_accept_init), 782 CA_MAIL_SERVER_SOLITARY, 783 CA_MAIL_SERVER_EXIT(verify_dump), 784 0); 785 } 786