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