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
flush_site_to_path(VSTRING * path,const char * site)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
flush_add_service(const char * site,const char * queue_id)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
flush_add_path(const char * path,const char * queue_id)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
flush_send_service(const char * site,int how)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
flush_one_file(const char * queue_id,VSTRING * queue_file,struct utimbuf * tbuf,int how)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
flush_send_path(const char * path,int how)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
flush_send_file_service(const char * queue_id)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
flush_refresh_service(int max_age)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
flush_request_receive(VSTREAM * client_stream,VSTRING * request)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
flush_service(VSTREAM * client_stream,char * unused_service,char ** argv)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
pre_jail_init(char * unused_name,char ** unused_argv)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
main(int argc,char ** argv)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