1 /* $NetBSD: flush.c,v 1.4 2022/10/08 16:12:45 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* flush 8 6 /* SUMMARY 7 /* Postfix fast flush server 8 /* SYNOPSIS 9 /* \fBflush\fR [generic Postfix daemon options] 10 /* DESCRIPTION 11 /* The \fBflush\fR(8) server maintains a record of deferred 12 /* mail by destination. 13 /* This information is used to improve the performance of the SMTP 14 /* \fBETRN\fR request, and of its command-line equivalent, 15 /* "\fBsendmail -qR\fR" or "\fBpostqueue -f\fR". 16 /* This program expects to be run from the \fBmaster\fR(8) process 17 /* manager. 18 /* 19 /* The record is implemented as a per-destination logfile with 20 /* as contents the queue IDs of deferred mail. A logfile is 21 /* append-only, and is truncated when delivery is requested 22 /* for the corresponding destination. A destination is the 23 /* part on the right-hand side of the right-most \fB@\fR in 24 /* an email address. 25 /* 26 /* Per-destination logfiles of deferred mail are maintained only for 27 /* eligible destinations. The list of eligible destinations is 28 /* specified with the \fBfast_flush_domains\fR configuration parameter, 29 /* which defaults to \fB$relay_domains\fR. 30 /* 31 /* This server implements the following requests: 32 /* .IP "\fBadd\fI sitename queueid\fR" 33 /* Inform the \fBflush\fR(8) server that the message with the specified 34 /* queue ID is queued for the specified destination. 35 /* .IP "\fBsend_site\fI sitename\fR" 36 /* Request delivery of mail that is queued for the specified 37 /* destination. 38 /* .IP "\fBsend_file\fI queueid\fR" 39 /* Request delivery of the specified deferred message. 40 /* .IP \fBrefresh\fR 41 /* Refresh non-empty per-destination logfiles that were not read in 42 /* \fB$fast_flush_refresh_time\fR hours, by simulating 43 /* send requests (see above) for the corresponding destinations. 44 /* .sp 45 /* Delete empty per-destination logfiles that were not updated in 46 /* \fB$fast_flush_purge_time\fR days. 47 /* .sp 48 /* This request completes in the background. 49 /* .IP \fBpurge\fR 50 /* Do a \fBrefresh\fR for all per-destination logfiles. 51 /* SECURITY 52 /* .ad 53 /* .fi 54 /* The \fBflush\fR(8) server is not security-sensitive. It does not 55 /* talk to the network, and it does not talk to local users. 56 /* The fast flush server can run chrooted at fixed low privilege. 57 /* DIAGNOSTICS 58 /* Problems and transactions are logged to \fBsyslogd\fR(8) 59 /* or \fBpostlogd\fR(8). 60 /* BUGS 61 /* Fast flush logfiles are truncated only after a "send" 62 /* request, not when mail is actually delivered, and therefore can 63 /* accumulate outdated or redundant data. In order to maintain sanity, 64 /* "refresh" must be executed periodically. This can 65 /* be automated with a suitable wakeup timer setting in the 66 /* \fBmaster.cf\fR configuration file. 67 /* 68 /* Upon receipt of a request to deliver mail for an eligible 69 /* destination, the \fBflush\fR(8) server requests delivery of all messages 70 /* that are listed in that destination's logfile, regardless of the 71 /* recipients of those messages. This is not an issue for mail 72 /* that is sent to a \fBrelay_domains\fR destination because 73 /* such mail typically only has recipients in one domain. 74 /* CONFIGURATION PARAMETERS 75 /* .ad 76 /* .fi 77 /* Changes to \fBmain.cf\fR are picked up automatically as \fBflush\fR(8) 78 /* processes run for only a limited amount of time. Use the command 79 /* "\fBpostfix reload\fR" to speed up a change. 80 /* 81 /* The text below provides only a parameter summary. See 82 /* \fBpostconf\fR(5) for more details including examples. 83 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR" 84 /* The default location of the Postfix main.cf and master.cf 85 /* configuration files. 86 /* .IP "\fBdaemon_timeout (18000s)\fR" 87 /* How much time a Postfix daemon process may take to handle a 88 /* request before it is terminated by a built-in watchdog timer. 89 /* .IP "\fBfast_flush_domains ($relay_domains)\fR" 90 /* Optional list of destinations that are eligible for per-destination 91 /* logfiles with mail that is queued to those destinations. 92 /* .IP "\fBfast_flush_refresh_time (12h)\fR" 93 /* The time after which a non-empty but unread per-destination "fast 94 /* flush" logfile needs to be refreshed. 95 /* .IP "\fBfast_flush_purge_time (7d)\fR" 96 /* The time after which an empty per-destination "fast flush" logfile 97 /* is deleted. 98 /* .IP "\fBipc_timeout (3600s)\fR" 99 /* The time limit for sending or receiving information over an internal 100 /* communication channel. 101 /* .IP "\fBmax_idle (100s)\fR" 102 /* The maximum amount of time that an idle Postfix daemon process waits 103 /* for an incoming connection before terminating voluntarily. 104 /* .IP "\fBmax_use (100)\fR" 105 /* The maximal number of incoming connections that a Postfix daemon 106 /* process will service before terminating voluntarily. 107 /* .IP "\fBparent_domain_matches_subdomains (see 'postconf -d' output)\fR" 108 /* A list of Postfix features where the pattern "example.com" also 109 /* matches subdomains of example.com, 110 /* instead of requiring an explicit ".example.com" pattern. 111 /* .IP "\fBprocess_id (read-only)\fR" 112 /* The process ID of a Postfix command or daemon process. 113 /* .IP "\fBprocess_name (read-only)\fR" 114 /* The process name of a Postfix command or daemon process. 115 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR" 116 /* The location of the Postfix top-level queue directory. 117 /* .IP "\fBsyslog_facility (mail)\fR" 118 /* The syslog facility of Postfix logging. 119 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR" 120 /* A prefix that is prepended to the process name in syslog 121 /* records, so that, for example, "smtpd" becomes "prefix/smtpd". 122 /* .PP 123 /* Available in Postfix 3.3 and later: 124 /* .IP "\fBservice_name (read-only)\fR" 125 /* The master.cf service name of a Postfix daemon process. 126 /* FILES 127 /* /var/spool/postfix/flush, "fast flush" logfiles. 128 /* SEE ALSO 129 /* smtpd(8), SMTP server 130 /* qmgr(8), queue manager 131 /* postconf(5), configuration parameters 132 /* master(5), generic daemon options 133 /* master(8), process manager 134 /* postlogd(8), Postfix logging 135 /* syslogd(8), system logging 136 /* README FILES 137 /* .ad 138 /* .fi 139 /* Use "\fBpostconf readme_directory\fR" or 140 /* "\fBpostconf html_directory\fR" to locate this information. 141 /* .na 142 /* .nf 143 /* ETRN_README, Postfix ETRN howto 144 /* LICENSE 145 /* .ad 146 /* .fi 147 /* The Secure Mailer license must be distributed with this software. 148 /* HISTORY 149 /* This service was introduced with Postfix version 1.0. 150 /* AUTHOR(S) 151 /* Wietse Venema 152 /* IBM T.J. Watson Research 153 /* P.O. Box 704 154 /* Yorktown Heights, NY 10598, USA 155 /* 156 /* Wietse Venema 157 /* Google, Inc. 158 /* 111 8th Avenue 159 /* New York, NY 10011, USA 160 /*--*/ 161 162 /* System library. */ 163 164 #include <sys_defs.h> 165 #include <sys/stat.h> 166 #include <sys/time.h> 167 #include <unistd.h> 168 #include <stdlib.h> 169 #include <utime.h> 170 #include <errno.h> 171 #include <ctype.h> 172 #include <string.h> 173 174 /* Utility library. */ 175 176 #include <msg.h> 177 #include <events.h> 178 #include <vstream.h> 179 #include <vstring.h> 180 #include <vstring_vstream.h> 181 #include <myflock.h> 182 #include <htable.h> 183 #include <dict.h> 184 #include <scan_dir.h> 185 #include <stringops.h> 186 #include <safe_open.h> 187 #include <warn_stat.h> 188 #include <midna_domain.h> 189 190 /* Global library. */ 191 192 #include <mail_params.h> 193 #include <mail_version.h> 194 #include <mail_queue.h> 195 #include <mail_proto.h> 196 #include <mail_flush.h> 197 #include <flush_clnt.h> 198 #include <mail_conf.h> 199 #include <mail_scan_dir.h> 200 #include <maps.h> 201 #include <domain_list.h> 202 #include <match_parent_style.h> 203 204 /* Single server skeleton. */ 205 206 #include <mail_server.h> 207 208 /* Application-specific. */ 209 210 /* 211 * Tunable parameters. The fast_flush_domains parameter is not defined here, 212 * because it is also used by the global library, and therefore is owned by 213 * the library. 214 */ 215 int var_fflush_refresh; 216 int var_fflush_purge; 217 218 /* 219 * Flush policy stuff. 220 */ 221 static DOMAIN_LIST *flush_domains; 222 223 /* 224 * Some hard-wired policy: how many queue IDs we remember while we're 225 * flushing a logfile (duplicate elimination). Sites with 1000+ emails 226 * queued should arrange for permanent connectivity. 227 */ 228 #define FLUSH_DUP_FILTER_SIZE 10000 /* graceful degradation */ 229 230 /* 231 * Silly little macros. 232 */ 233 #define STR(x) vstring_str(x) 234 #define STREQ(x,y) (STRREF(x) == STRREF(y) || strcmp(x,y) == 0) 235 236 /* 237 * Forward declarations resulting from breaking up routines according to 238 * name space: domain names versus safe-to-use pathnames. 239 */ 240 static int flush_add_path(const char *, const char *); 241 static int flush_send_path(const char *, int); 242 243 /* 244 * Do we only refresh the per-destination logfile, or do we really request 245 * mail delivery as if someone sent ETRN? If the latter, we must override 246 * information about unavailable hosts or unavailable transports. 247 * 248 * When selectively flushing deferred mail, we need to override the queue 249 * manager's "dead destination" information and unthrottle transports and 250 * queues. There are two options: 251 * 252 * - Unthrottle all transports and queues before we move mail to the incoming 253 * queue. This is less accurate, but has the advantage when flushing lots of 254 * mail, because Postfix can skip delivery of flushed messages after it 255 * discovers that a destination is (still) unavailable. 256 * 257 * - Unthrottle some transports and queues after the queue manager moves mail 258 * to the active queue. This is more accurate, but has the disadvantage when 259 * flushing lots of mail, because Postfix cannot skip delivery of flushed 260 * messages after it discovers that a destination is (still) unavailable. 261 */ 262 #define REFRESH_ONLY 0 263 #define UNTHROTTLE_BEFORE (1<<0) 264 #define UNTHROTTLE_AFTER (1<<1) 265 266 /* flush_site_to_path - convert domain or [addr] to harmless string */ 267 268 static VSTRING *flush_site_to_path(VSTRING *path, const char *site) 269 { 270 const char *ptr; 271 int ch; 272 273 /* 274 * Convert the name to ASCII, so that we don't to end up with non-ASCII 275 * names in the file system. The IDNA library functions fold case. 276 */ 277 #ifndef NO_EAI 278 if ((site = midna_domain_to_ascii(site)) == 0) 279 return (0); 280 #endif 281 282 /* 283 * Allocate buffer on the fly; caller still needs to clean up. 284 */ 285 if (path == 0) 286 path = vstring_alloc(10); 287 288 /* 289 * Mask characters that could upset the name-to-queue-file mapping code. 290 */ 291 for (ptr = site; (ch = *(unsigned const char *) ptr) != 0; ptr++) 292 if (ISALNUM(ch)) 293 VSTRING_ADDCH(path, tolower(ch)); 294 else 295 VSTRING_ADDCH(path, '_'); 296 VSTRING_TERMINATE(path); 297 298 if (msg_verbose) 299 msg_info("site %s to path %s", site, STR(path)); 300 301 return (path); 302 } 303 304 /* flush_add_service - append queue ID to per-site fast flush logfile */ 305 306 static int flush_add_service(const char *site, const char *queue_id) 307 { 308 const char *myname = "flush_add_service"; 309 VSTRING *site_path; 310 int status; 311 312 if (msg_verbose) 313 msg_info("%s: site %s queue_id %s", myname, site, queue_id); 314 315 /* 316 * If this site is not eligible for logging, deny the request. 317 */ 318 if (domain_list_match(flush_domains, site) == 0) 319 return (flush_domains->error ? FLUSH_STAT_FAIL : FLUSH_STAT_DENY); 320 321 /* 322 * Map site to path and update log. 323 */ 324 if ((site_path = flush_site_to_path((VSTRING *) 0, site)) == 0) 325 return (FLUSH_STAT_DENY); 326 status = flush_add_path(STR(site_path), queue_id); 327 vstring_free(site_path); 328 329 return (status); 330 } 331 332 /* flush_add_path - add record to log */ 333 334 static int flush_add_path(const char *path, const char *queue_id) 335 { 336 const char *myname = "flush_add_path"; 337 VSTREAM *log; 338 339 /* 340 * Sanity check. 341 */ 342 if (!mail_queue_id_ok(path)) 343 return (FLUSH_STAT_BAD); 344 345 /* 346 * Open the logfile or bust. 347 */ 348 if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, path, 349 O_CREAT | O_APPEND | O_WRONLY, 0600)) == 0) 350 msg_fatal("%s: open fast flush logfile %s: %m", myname, path); 351 352 /* 353 * We must lock the logfile, so that we don't lose information due to 354 * concurrent access. If the lock takes too long, the Postfix watchdog 355 * will eventually take care of the problem, but it will take a while. 356 */ 357 if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) 358 msg_fatal("%s: lock fast flush logfile %s: %m", myname, path); 359 360 /* 361 * Append the queue ID. With 15 bits of microsecond time, a queue ID is 362 * not recycled often enough for false hits to be a problem. If it does, 363 * then we could add other signature information, such as the file size 364 * in bytes. 365 */ 366 vstream_fprintf(log, "%s\n", queue_id); 367 if (vstream_fflush(log)) 368 msg_warn("write fast flush logfile %s: %m", path); 369 370 /* 371 * Clean up. 372 */ 373 if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) 374 msg_fatal("%s: unlock fast flush logfile %s: %m", myname, path); 375 if (vstream_fclose(log) != 0) 376 msg_warn("write fast flush logfile %s: %m", path); 377 378 return (FLUSH_STAT_OK); 379 } 380 381 /* flush_send_service - flush mail queued for site */ 382 383 static int flush_send_service(const char *site, int how) 384 { 385 const char *myname = "flush_send_service"; 386 VSTRING *site_path; 387 int status; 388 389 if (msg_verbose) 390 msg_info("%s: site %s", myname, site); 391 392 /* 393 * If this site is not eligible for logging, deny the request. 394 */ 395 if (domain_list_match(flush_domains, site) == 0) 396 return (flush_domains->error ? FLUSH_STAT_FAIL : FLUSH_STAT_DENY); 397 398 /* 399 * Map site name to path name and flush the log. 400 */ 401 if ((site_path = flush_site_to_path((VSTRING *) 0, site)) == 0) 402 return (FLUSH_STAT_DENY); 403 status = flush_send_path(STR(site_path), how); 404 vstring_free(site_path); 405 406 return (status); 407 } 408 409 /* flush_one_file - move one queue file to incoming queue */ 410 411 static int flush_one_file(const char *queue_id, VSTRING *queue_file, 412 struct utimbuf * tbuf, int how) 413 { 414 const char *myname = "flush_one_file"; 415 const char *queue_name; 416 const char *path; 417 418 /* 419 * Some other instance of this program may flush some logfile and may 420 * just have moved this queue file to the incoming queue. 421 */ 422 for (queue_name = MAIL_QUEUE_DEFERRED; /* see below */ ; 423 queue_name = MAIL_QUEUE_INCOMING) { 424 path = mail_queue_path(queue_file, queue_name, queue_id); 425 if (utime(path, tbuf) == 0) 426 break; 427 if (errno != ENOENT) 428 msg_warn("%s: update %s time stamps: %m", myname, path); 429 if (STREQ(queue_name, MAIL_QUEUE_INCOMING)) 430 return (0); 431 } 432 433 /* 434 * With the UNTHROTTLE_AFTER strategy, we leave it up to the queue 435 * manager to unthrottle transports and queues as it reads recipients 436 * from a queue file. We request this unthrottle operation by setting the 437 * group read permission bit. 438 * 439 * Note: we must avoid using chmod(). It is not only slower than fchmod() 440 * but it is also less secure. With chmod(), an attacker could repeatedly 441 * send requests to the flush server and trick it into changing 442 * permissions of non-queue files, by exploiting a race condition. 443 * 444 * We use safe_open() because we don't validate the file content before 445 * modifying the file status. 446 */ 447 if (how & UNTHROTTLE_AFTER) { 448 VSTRING *why; 449 struct stat st; 450 VSTREAM *fp; 451 452 for (why = vstring_alloc(1); /* see below */ ; 453 queue_name = MAIL_QUEUE_INCOMING, 454 path = mail_queue_path(queue_file, queue_name, queue_id)) { 455 if ((fp = safe_open(path, O_RDWR, 0, &st, -1, -1, why)) != 0) 456 break; 457 if (errno != ENOENT) 458 msg_warn("%s: open %s: %s", myname, path, STR(why)); 459 if (errno != ENOENT || STREQ(queue_name, MAIL_QUEUE_INCOMING)) { 460 vstring_free(why); 461 return (0); 462 } 463 } 464 vstring_free(why); 465 if ((st.st_mode & MAIL_QUEUE_STAT_READY) != MAIL_QUEUE_STAT_READY) { 466 (void) vstream_fclose(fp); 467 return (0); 468 } 469 if (fchmod(vstream_fileno(fp), st.st_mode | MAIL_QUEUE_STAT_UNTHROTTLE) < 0) 470 msg_warn("%s: fchmod %s: %m", myname, path); 471 (void) vstream_fclose(fp); 472 } 473 474 /* 475 * Move the file to the incoming queue, if it isn't already there. 476 */ 477 if (STREQ(queue_name, MAIL_QUEUE_INCOMING) == 0 478 && mail_queue_rename(queue_id, queue_name, MAIL_QUEUE_INCOMING) < 0 479 && errno != ENOENT) 480 msg_warn("%s: rename from %s to %s: %m", 481 path, queue_name, MAIL_QUEUE_INCOMING); 482 483 /* 484 * If we got here, we achieved something, so let's claim success. 485 */ 486 return (1); 487 } 488 489 /* flush_send_path - flush logfile file */ 490 491 static int flush_send_path(const char *path, int how) 492 { 493 const char *myname = "flush_send_path"; 494 VSTRING *queue_id; 495 VSTRING *queue_file; 496 VSTREAM *log; 497 struct utimbuf tbuf; 498 static char qmgr_flush_trigger[] = { 499 QMGR_REQ_FLUSH_DEAD, /* flush dead site/transport cache */ 500 }; 501 static char qmgr_scan_trigger[] = { 502 QMGR_REQ_SCAN_INCOMING, /* scan incoming queue */ 503 }; 504 HTABLE *dup_filter; 505 int count; 506 507 /* 508 * Sanity check. 509 */ 510 if (!mail_queue_id_ok(path)) 511 return (FLUSH_STAT_BAD); 512 513 /* 514 * Open the logfile. If the file does not exist, then there is no queued 515 * mail for this destination. 516 */ 517 if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, path, O_RDWR, 0600)) == 0) { 518 if (errno != ENOENT) 519 msg_fatal("%s: open fast flush logfile %s: %m", myname, path); 520 return (FLUSH_STAT_OK); 521 } 522 523 /* 524 * We must lock the logfile, so that we don't lose information when it is 525 * truncated. Unfortunately, this means that the file can be locked for a 526 * significant amount of time. If things really get stuck the Postfix 527 * watchdog will take care of it. 528 */ 529 if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) 530 msg_fatal("%s: lock fast flush logfile %s: %m", myname, path); 531 532 /* 533 * With the UNTHROTTLE_BEFORE strategy, we ask the queue manager to 534 * unthrottle all transports and queues before we move a deferred queue 535 * file to the incoming queue. This minimizes a race condition where the 536 * queue manager seizes a queue file before it knows that we want to 537 * flush that message. 538 * 539 * This reduces the race condition time window to a very small amount (the 540 * flush server does not really know when the queue manager reads its 541 * command fifo). But there is a worse race, where the queue manager 542 * moves a deferred queue file to the active queue before we have a 543 * chance to expedite its delivery. 544 */ 545 if (how & UNTHROTTLE_BEFORE) 546 mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, 547 qmgr_flush_trigger, sizeof(qmgr_flush_trigger)); 548 549 /* 550 * This is the part that dominates running time: schedule the listed 551 * queue files for delivery by updating their file time stamps and by 552 * moving them from the deferred queue to the incoming queue. This should 553 * take no more than a couple seconds under normal conditions. Filter out 554 * duplicate queue file names to avoid hammering the file system, with 555 * some finite limit on the amount of memory that we are willing to 556 * sacrifice for duplicate filtering. Graceful degradation. 557 * 558 * By moving selected queue files from the deferred queue to the incoming 559 * queue we optimize for the case where most deferred mail is for other 560 * sites. If that assumption does not hold, i.e. all deferred mail is for 561 * the same site, then doing a "fast flush" will cost more disk I/O than 562 * a "slow flush" that delivers the entire deferred queue. This penalty 563 * is only temporary - it will go away after we unite the active queue 564 * and the incoming queue. 565 */ 566 queue_id = vstring_alloc(10); 567 queue_file = vstring_alloc(10); 568 dup_filter = htable_create(10); 569 tbuf.actime = tbuf.modtime = event_time(); 570 for (count = 0; vstring_get_nonl(queue_id, log) != VSTREAM_EOF; count++) { 571 if (!mail_queue_id_ok(STR(queue_id))) { 572 msg_warn("bad queue id \"%.30s...\" in fast flush logfile %s", 573 STR(queue_id), path); 574 continue; 575 } 576 if (dup_filter->used >= FLUSH_DUP_FILTER_SIZE 577 || htable_find(dup_filter, STR(queue_id)) == 0) { 578 if (msg_verbose) 579 msg_info("%s: logfile %s: update queue file %s time stamps", 580 myname, path, STR(queue_id)); 581 if (dup_filter->used <= FLUSH_DUP_FILTER_SIZE) 582 htable_enter(dup_filter, STR(queue_id), 0); 583 count += flush_one_file(STR(queue_id), queue_file, &tbuf, how); 584 } else { 585 if (msg_verbose) 586 msg_info("%s: logfile %s: skip queue file %s as duplicate", 587 myname, path, STR(queue_file)); 588 } 589 } 590 htable_free(dup_filter, (void (*) (void *)) 0); 591 vstring_free(queue_file); 592 vstring_free(queue_id); 593 594 /* 595 * Truncate the fast flush log. 596 */ 597 if (count > 0 && ftruncate(vstream_fileno(log), (off_t) 0) < 0) 598 msg_fatal("%s: truncate fast flush logfile %s: %m", myname, path); 599 600 /* 601 * Workaround for noatime mounts. Use futimes() if available. 602 */ 603 (void) utimes(VSTREAM_PATH(log), (struct timeval *) 0); 604 605 /* 606 * Request delivery and clean up. 607 */ 608 if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) 609 msg_fatal("%s: unlock fast flush logfile %s: %m", myname, path); 610 if (vstream_fclose(log) != 0) 611 msg_warn("%s: read fast flush logfile %s: %m", myname, path); 612 if (count > 0) { 613 if (msg_verbose) 614 msg_info("%s: requesting delivery for logfile %s", myname, path); 615 mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, 616 qmgr_scan_trigger, sizeof(qmgr_scan_trigger)); 617 } 618 return (FLUSH_STAT_OK); 619 } 620 621 /* flush_send_file_service - flush one queue file */ 622 623 static int flush_send_file_service(const char *queue_id) 624 { 625 const char *myname = "flush_send_file_service"; 626 VSTRING *queue_file; 627 struct utimbuf tbuf; 628 static char qmgr_scan_trigger[] = { 629 QMGR_REQ_SCAN_INCOMING, /* scan incoming queue */ 630 }; 631 632 /* 633 * Sanity check. 634 */ 635 if (!mail_queue_id_ok(queue_id)) 636 return (FLUSH_STAT_BAD); 637 638 if (msg_verbose) 639 msg_info("%s: requesting delivery for queue_id %s", myname, queue_id); 640 641 queue_file = vstring_alloc(30); 642 tbuf.actime = tbuf.modtime = event_time(); 643 if (flush_one_file(queue_id, queue_file, &tbuf, UNTHROTTLE_AFTER) > 0) 644 mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, 645 qmgr_scan_trigger, sizeof(qmgr_scan_trigger)); 646 vstring_free(queue_file); 647 648 return (FLUSH_STAT_OK); 649 } 650 651 /* flush_refresh_service - refresh logfiles beyond some age */ 652 653 static int flush_refresh_service(int max_age) 654 { 655 const char *myname = "flush_refresh_service"; 656 SCAN_DIR *scan; 657 char *site_path; 658 struct stat st; 659 VSTRING *path = vstring_alloc(10); 660 661 scan = scan_dir_open(MAIL_QUEUE_FLUSH); 662 while ((site_path = mail_scan_dir_next(scan)) != 0) { 663 if (!mail_queue_id_ok(site_path)) 664 continue; /* XXX grumble. */ 665 mail_queue_path(path, MAIL_QUEUE_FLUSH, site_path); 666 if (stat(STR(path), &st) < 0) { 667 if (errno != ENOENT) 668 msg_warn("%s: stat %s: %m", myname, STR(path)); 669 else if (msg_verbose) 670 msg_info("%s: %s: %m", myname, STR(path)); 671 continue; 672 } 673 if (st.st_size == 0) { 674 if (st.st_mtime + var_fflush_purge < event_time()) { 675 if (unlink(STR(path)) < 0) 676 msg_warn("remove logfile %s: %m", STR(path)); 677 else if (msg_verbose) 678 msg_info("%s: unlink %s, empty and unchanged for %d days", 679 myname, STR(path), var_fflush_purge / 86400); 680 } else if (msg_verbose) 681 msg_info("%s: skip logfile %s - empty log", myname, site_path); 682 } else if (st.st_atime + max_age < event_time()) { 683 if (msg_verbose) 684 msg_info("%s: flush logfile %s", myname, site_path); 685 flush_send_path(site_path, REFRESH_ONLY); 686 } else { 687 if (msg_verbose) 688 msg_info("%s: skip logfile %s, unread for <%d hours(s) ", 689 myname, site_path, max_age / 3600); 690 } 691 } 692 scan_dir_close(scan); 693 vstring_free(path); 694 695 return (FLUSH_STAT_OK); 696 } 697 698 /* flush_request_receive - receive request */ 699 700 static int flush_request_receive(VSTREAM *client_stream, VSTRING *request) 701 { 702 int count; 703 704 /* 705 * Announce the protocol. 706 */ 707 attr_print(client_stream, ATTR_FLAG_NONE, 708 SEND_ATTR_STR(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_FLUSH), 709 ATTR_TYPE_END); 710 (void) vstream_fflush(client_stream); 711 712 /* 713 * Kluge: choose the protocol depending on the request size. 714 */ 715 if (read_wait(vstream_fileno(client_stream), var_ipc_timeout) < 0) { 716 msg_warn("timeout while waiting for data from %s", 717 VSTREAM_PATH(client_stream)); 718 return (-1); 719 } 720 if ((count = peekfd(vstream_fileno(client_stream))) < 0) { 721 msg_warn("cannot examine read buffer of %s: %m", 722 VSTREAM_PATH(client_stream)); 723 return (-1); 724 } 725 726 /* 727 * Short request: master trigger. Use the string+null protocol. 728 */ 729 if (count <= 2) { 730 if (vstring_get_null(request, client_stream) == VSTREAM_EOF) { 731 msg_warn("end-of-input while reading request from %s: %m", 732 VSTREAM_PATH(client_stream)); 733 return (-1); 734 } 735 } 736 737 /* 738 * Long request: real flush client. Use the attribute list protocol. 739 */ 740 else { 741 if (attr_scan(client_stream, 742 ATTR_FLAG_MORE | ATTR_FLAG_STRICT, 743 RECV_ATTR_STR(MAIL_ATTR_REQ, request), 744 ATTR_TYPE_END) != 1) { 745 return (-1); 746 } 747 } 748 return (0); 749 } 750 751 /* flush_service - perform service for client */ 752 753 static void flush_service(VSTREAM *client_stream, char *unused_service, 754 char **argv) 755 { 756 VSTRING *request = vstring_alloc(10); 757 VSTRING *site = 0; 758 VSTRING *queue_id = 0; 759 static char wakeup[] = { /* master wakeup request */ 760 TRIGGER_REQ_WAKEUP, 761 0, 762 }; 763 int status = FLUSH_STAT_BAD; 764 765 /* 766 * Sanity check. This service takes no command-line arguments. 767 */ 768 if (argv[0]) 769 msg_fatal("unexpected command-line argument: %s", argv[0]); 770 771 /* 772 * This routine runs whenever a client connects to the UNIX-domain socket 773 * dedicated to the fast flush service. What we see below is a little 774 * protocol to (1) read a request from the client (the name of the site) 775 * and (2) acknowledge that we have received the request. 776 * 777 * All connection-management stuff is handled by the common code in 778 * single_server.c. 779 */ 780 if (flush_request_receive(client_stream, request) == 0) { 781 if (STREQ(STR(request), FLUSH_REQ_ADD)) { 782 site = vstring_alloc(10); 783 queue_id = vstring_alloc(10); 784 if (attr_scan(client_stream, ATTR_FLAG_STRICT, 785 RECV_ATTR_STR(MAIL_ATTR_SITE, site), 786 RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id), 787 ATTR_TYPE_END) == 2 788 && mail_queue_id_ok(STR(queue_id))) 789 status = flush_add_service(STR(site), STR(queue_id)); 790 attr_print(client_stream, ATTR_FLAG_NONE, 791 SEND_ATTR_INT(MAIL_ATTR_STATUS, status), 792 ATTR_TYPE_END); 793 } else if (STREQ(STR(request), FLUSH_REQ_SEND_SITE)) { 794 site = vstring_alloc(10); 795 if (attr_scan(client_stream, ATTR_FLAG_STRICT, 796 RECV_ATTR_STR(MAIL_ATTR_SITE, site), 797 ATTR_TYPE_END) == 1) 798 status = flush_send_service(STR(site), UNTHROTTLE_BEFORE); 799 attr_print(client_stream, ATTR_FLAG_NONE, 800 SEND_ATTR_INT(MAIL_ATTR_STATUS, status), 801 ATTR_TYPE_END); 802 } else if (STREQ(STR(request), FLUSH_REQ_SEND_FILE)) { 803 queue_id = vstring_alloc(10); 804 if (attr_scan(client_stream, ATTR_FLAG_STRICT, 805 RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id), 806 ATTR_TYPE_END) == 1) 807 status = flush_send_file_service(STR(queue_id)); 808 attr_print(client_stream, ATTR_FLAG_NONE, 809 SEND_ATTR_INT(MAIL_ATTR_STATUS, status), 810 ATTR_TYPE_END); 811 } else if (STREQ(STR(request), FLUSH_REQ_REFRESH) 812 || STREQ(STR(request), wakeup)) { 813 attr_print(client_stream, ATTR_FLAG_NONE, 814 SEND_ATTR_INT(MAIL_ATTR_STATUS, FLUSH_STAT_OK), 815 ATTR_TYPE_END); 816 vstream_fflush(client_stream); 817 (void) flush_refresh_service(var_fflush_refresh); 818 } else if (STREQ(STR(request), FLUSH_REQ_PURGE)) { 819 attr_print(client_stream, ATTR_FLAG_NONE, 820 SEND_ATTR_INT(MAIL_ATTR_STATUS, FLUSH_STAT_OK), 821 ATTR_TYPE_END); 822 vstream_fflush(client_stream); 823 (void) flush_refresh_service(0); 824 } 825 } else 826 attr_print(client_stream, ATTR_FLAG_NONE, 827 SEND_ATTR_INT(MAIL_ATTR_STATUS, status), 828 ATTR_TYPE_END); 829 vstring_free(request); 830 if (site) 831 vstring_free(site); 832 if (queue_id) 833 vstring_free(queue_id); 834 } 835 836 /* pre_jail_init - pre-jail initialization */ 837 838 static void pre_jail_init(char *unused_name, char **unused_argv) 839 { 840 flush_domains = domain_list_init(VAR_FFLUSH_DOMAINS, MATCH_FLAG_RETURN 841 | match_parent_style(VAR_FFLUSH_DOMAINS), 842 var_fflush_domains); 843 } 844 845 MAIL_VERSION_STAMP_DECLARE; 846 847 /* main - pass control to the single-threaded skeleton */ 848 849 int main(int argc, char **argv) 850 { 851 static const CONFIG_TIME_TABLE time_table[] = { 852 VAR_FFLUSH_REFRESH, DEF_FFLUSH_REFRESH, &var_fflush_refresh, 1, 0, 853 VAR_FFLUSH_PURGE, DEF_FFLUSH_PURGE, &var_fflush_purge, 1, 0, 854 0, 855 }; 856 857 /* 858 * Fingerprint executables and core dumps. 859 */ 860 MAIL_VERSION_STAMP_ALLOCATE; 861 862 single_server_main(argc, argv, flush_service, 863 CA_MAIL_SERVER_TIME_TABLE(time_table), 864 CA_MAIL_SERVER_PRE_INIT(pre_jail_init), 865 CA_MAIL_SERVER_UNLIMITED, 866 0); 867 } 868