1 /*	$NetBSD: postsuper.c,v 1.4 2022/10/08 16:12:48 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	postsuper 1
6 /* SUMMARY
7 /*	Postfix superintendent
8 /* SYNOPSIS
9 /* .fi
10 /*	\fBpostsuper\fR [\fB-psSv\fR]
11 /*		[\fB-c \fIconfig_dir\fR] [\fB-d \fIqueue_id\fR]
12 /*		[\fB-e \fIqueue_id\fR] [\fB-f \fIqueue_id\fR]
13 /*		[\fB-h \fIqueue_id\fR] [\fB-H \fIqueue_id\fR]
14 /*		[\fB-r \fIqueue_id\fR] [\fIdirectory ...\fR]
15 /* DESCRIPTION
16 /*	The \fBpostsuper\fR(1) command does maintenance jobs on the Postfix
17 /*	queue. Use of the command is restricted to the superuser.
18 /*	See the \fBpostqueue\fR(1) command for unprivileged queue operations
19 /*	such as listing or flushing the mail queue.
20 /*
21 /*	By default, \fBpostsuper\fR(1) performs the operations
22 /*	requested with the
23 /*	\fB-s\fR and \fB-p\fR command-line options on all Postfix queue
24 /*	directories - this includes the \fBincoming\fR, \fBactive\fR,
25 /*	\fBdeferred\fR, and \fBhold\fR directories with message
26 /*	files and the \fBbounce\fR,
27 /*	\fBdefer\fR, \fBtrace\fR and \fBflush\fR directories with log files.
28 /*
29 /*	Options:
30 /* .IP "\fB-c \fIconfig_dir\fR"
31 /*	The \fBmain.cf\fR configuration file is in the named directory
32 /*	instead of the default configuration directory. See also the
33 /*	MAIL_CONFIG environment setting below.
34 /* .IP "\fB-d \fIqueue_id\fR"
35 /*	Delete one message with the named queue ID from the named
36 /*	mail queue(s) (default: \fBhold\fR, \fBincoming\fR, \fBactive\fR and
37 /*	\fBdeferred\fR).
38 /*
39 /*	To delete multiple files, specify the \fB-d\fR option multiple
40 /*	times, or specify a \fIqueue_id\fR of \fB-\fR to read queue IDs
41 /*	from standard input. For example, to delete all mail
42 /*	with exactly one recipient \fBuser@example.com\fR:
43 /* .sp
44 /* .nf
45 /*	postqueue -j | jq -r '
46 /*	    # See JSON OBJECT FORMAT section in the postqueue(1) manpage
47 /*	    select(.recipients[0].address == "user@example.com")
48 /*	    | select(.recipients[1].address == null)
49 /*	    | .queue_id
50 /*	 ' | postsuper -d -
51 /* .fi
52 /* .sp
53 /*	(note the "jq -r" option), or the historical form:
54 /* .sp
55 /* .nf
56 /*	mailq | tail -n +2 | grep -v '^ *(' | awk  'BEGIN { RS = "" }
57 /*	    # $7=sender, $8=recipient1, $9=recipient2
58 /*	    { if ($8 == "user@example.com" && $9 == "")
59 /*	          print $1 }
60 /*	 ' | tr -d '*!' | postsuper -d -
61 /* .fi
62 /* .sp
63 /*	Specify "\fB-d ALL\fR" to remove all messages; for example, specify
64 /*	"\fB-d ALL deferred\fR" to delete all mail in the \fBdeferred\fR queue.
65 /*	As a safety measure, the word \fBALL\fR must be specified in upper
66 /*	case.
67 /* .sp
68 /*	Warning: Postfix queue IDs are reused (always with Postfix
69 /*	<= 2.8; and with Postfix >= 2.9 when enable_long_queue_ids=no).
70 /*	There is a very small possibility that postsuper deletes the
71 /*	wrong message file when it is executed while the Postfix mail
72 /*	system is delivering mail.
73 /* .sp
74 /*	The scenario is as follows:
75 /* .RS
76 /* .IP 1)
77 /*	The Postfix queue manager deletes the message that \fBpostsuper\fR(1)
78 /*	is asked to delete, because Postfix is finished with the
79 /*	message (it is delivered, or it is returned to the sender).
80 /* .IP 2)
81 /*	New mail arrives, and the new message is given the same queue ID
82 /*	as the message that \fBpostsuper\fR(1) is supposed to delete.
83 /*	The probability for reusing a deleted queue ID is about 1 in 2**15
84 /*	(the number of different microsecond values that the system clock
85 /*	can distinguish within a second).
86 /* .IP 3)
87 /*	\fBpostsuper\fR(1) deletes the new message, instead of the old
88 /*	message that it should have deleted.
89 /* .RE
90 /* .IP "\fB-e \fIqueue_id\fR"
91 /* .IP "\fB-f \fIqueue_id\fR"
92 /*	Request forced expiration for one message with the named
93 /*	queue ID in the named mail queue(s) (default: \fBhold\fR,
94 /*	\fBincoming\fR, \fBactive\fR and \fBdeferred\fR).
95 /* .RS
96 /* .IP \(bu
97 /*	The message will be returned to the sender when the queue
98 /*	manager attempts to deliver that message (note that Postfix
99 /*	will never deliver messages in the \fBhold\fR queue).
100 /* .IP \(bu
101 /*	The \fB-e\fR and \fB-f\fR options both request forced
102 /*	expiration. The difference is that \fB-f\fR will also release
103 /*	a message if it is in the \fBhold\fR queue. With \fB-e\fR, such
104 /*	a message would not be returned to the sender until it is
105 /*	released with \fB-f\fR or \fB-H\fR.
106 /* .IP \(bu
107 /*	When a deferred message is force-expired, the return message
108 /*	will state the reason for the delay. Otherwise, the reason
109 /*	will be "message is administratively expired".
110 /* .RE
111 /* .IP
112 /*	To expire multiple files, specify the \fB-e\fR or \fB-f\fR
113 /*	option multiple times, or specify a \fIqueue_id\fR of \fB-\fR
114 /*	to read queue IDs from standard input (see the \fB-d\fR option
115 /*	above for an example, but be sure to replace \fB-d\fR in
116 /*	the example).
117 /* .sp
118 /*	Specify "\fB-e ALL\fR" or "\fB-f ALL\fR" to expire all
119 /*	messages; for example, specify "\fB-e ALL deferred\fR" to
120 /*	expire all mail in the \fBdeferred\fR queue.  As a safety
121 /*	measure, the word \fBALL\fR must be specified in upper case.
122 /* .sp
123 /*	These features are available in Postfix 3.5 and later.
124 /* .IP "\fB-h \fIqueue_id\fR"
125 /*	Put mail "on hold" so that no attempt is made to deliver it.
126 /*	Move one message with the named queue ID from the named
127 /*	mail queue(s) (default: \fBincoming\fR, \fBactive\fR and
128 /*	\fBdeferred\fR) to the \fBhold\fR queue.
129 /*
130 /*	To hold multiple files, specify the \fB-h\fR option multiple
131 /*	times, or specify a \fIqueue_id\fR of \fB-\fR to read queue IDs
132 /*	from standard input.
133 /* .sp
134 /*	Specify "\fB-h ALL\fR" to hold all messages; for example, specify
135 /*	"\fB-h ALL deferred\fR" to hold all mail in the \fBdeferred\fR queue.
136 /*	As a safety measure, the word \fBALL\fR must be specified in upper
137 /*	case.
138 /* .sp
139 /*	Note: while mail is "on hold" it will not expire when its
140 /*	time in the queue exceeds the \fBmaximal_queue_lifetime\fR
141 /*	or \fBbounce_queue_lifetime\fR setting. It becomes subject to
142 /*	expiration after it is released from "hold".
143 /* .sp
144 /*	This feature is available in Postfix 2.0 and later.
145 /* .IP "\fB-H \fIqueue_id\fR"
146 /*	Release mail that was put "on hold".
147 /*	Move one message with the named queue ID from the named
148 /*	mail queue(s) (default: \fBhold\fR) to the \fBdeferred\fR queue.
149 /*
150 /*	To release multiple files, specify the \fB-H\fR option multiple
151 /*	times, or specify a \fIqueue_id\fR of \fB-\fR to read queue IDs
152 /*	from standard input.
153 /* .sp
154 /*	Note: specify "\fBpostsuper -r\fR" to release mail that was kept on
155 /*	hold for a significant fraction of \fB$maximal_queue_lifetime\fR
156 /*	or \fB$bounce_queue_lifetime\fR, or longer.
157 /* .sp
158 /*	Specify "\fB-H ALL\fR" to release all mail that is "on hold".
159 /*	As a safety measure, the word \fBALL\fR must be specified in upper
160 /*	case.
161 /* .sp
162 /*	This feature is available in Postfix 2.0 and later.
163 /* .IP \fB-p\fR
164 /*	Purge old temporary files that are left over after system or
165 /*	software crashes.
166 /*	The \fB-p\fR, \fB-s\fR, and \fB-S\fR operations are done
167 /*	before other operations.
168 /* .IP "\fB-r \fIqueue_id\fR"
169 /*	Requeue the message with the named queue ID from the named
170 /*	mail queue(s) (default: \fBhold\fR, \fBincoming\fR, \fBactive\fR and
171 /*	\fBdeferred\fR).
172 /*
173 /*	To requeue multiple files, specify the \fB-r\fR option multiple
174 /*	times, or specify a \fIqueue_id\fR of \fB-\fR to read queue IDs
175 /*	from standard input.
176 /* .sp
177 /*	Specify "\fB-r ALL\fR" to requeue all messages. As a safety
178 /*	measure, the word \fBALL\fR must be specified in upper case.
179 /* .sp
180 /*	A requeued message is moved to the \fBmaildrop\fR queue,
181 /*	from where it is copied by the \fBpickup\fR(8) and
182 /*	\fBcleanup\fR(8) daemons to a new queue file. In many
183 /*	respects its handling differs from that of a new local
184 /*	submission.
185 /* .RS
186 /* .IP \(bu
187 /*	The message is not subjected to the smtpd_milters or
188 /*	non_smtpd_milters settings.  When mail has passed through
189 /*	an external content filter, this would produce incorrect
190 /*	results with Milter applications that depend on original
191 /*	SMTP connection state information.
192 /* .IP \(bu
193 /*	The message is subjected again to mail address rewriting
194 /*	and substitution.  This is useful when rewriting rules or
195 /*	virtual mappings have changed.
196 /* .sp
197 /*	The address rewriting context (local or remote) is the same
198 /*	as when the message was received.
199 /* .IP \(bu
200 /*	The message is subjected to the same content_filter settings
201 /*	(if any) as used for new local mail submissions.  This is
202 /*	useful when content_filter settings have changed.
203 /* .RE
204 /* .IP
205 /*	Warning: Postfix queue IDs are reused (always with Postfix
206 /*	<= 2.8; and with Postfix >= 2.9 when enable_long_queue_ids=no).
207 /*	There is a very small possibility that \fBpostsuper\fR(1) requeues
208 /*	the wrong message file when it is executed while the Postfix mail
209 /*	system is running, but no harm should be done.
210 /* .sp
211 /*	This feature is available in Postfix 1.1 and later.
212 /* .IP \fB-s\fR
213 /*	Structure check and structure repair.  This should be done once
214 /*	before Postfix startup.
215 /*	The \fB-p\fR, \fB-s\fR, and \fB-S\fR operations are done
216 /*	before other operations.
217 /* .RS
218 /* .IP \(bu
219 /*	Rename files whose name does not match the message file inode
220 /*	number. This operation is necessary after restoring a mail
221 /*	queue from a different machine or from backup, when queue
222 /*	files were created with Postfix <= 2.8 or with
223 /*	"enable_long_queue_ids = no".
224 /* .IP \(bu
225 /*	Move queue files that are in the wrong place in the file system
226 /*	hierarchy and remove subdirectories that are no longer needed.
227 /*	File position rearrangements are necessary after a change in the
228 /*	\fBhash_queue_names\fR and/or \fBhash_queue_depth\fR
229 /*	configuration parameters.
230 /* .IP \(bu
231 /*	Rename queue files created with "enable_long_queue_ids =
232 /*	yes" to short names, for migration to Postfix <= 2.8.  The
233 /*	procedure is as follows:
234 /* .sp
235 /* .nf
236 /* .na
237 /*	# postfix stop
238 /*	# postconf enable_long_queue_ids=no
239 /*	# postsuper
240 /* .ad
241 /* .fi
242 /* .sp
243 /*	Run \fBpostsuper\fR(1) repeatedly until it stops reporting
244 /*	file name changes.
245 /* .RE
246 /* .IP \fB-S\fR
247 /*	A redundant version of \fB-s\fR that requires that long
248 /*	file names also match the message file inode number. This
249 /*	option exists for testing purposes, and is available with
250 /*	Postfix 2.9 and later.
251 /*	The \fB-p\fR, \fB-s\fR, and \fB-S\fR operations are done
252 /*	before other operations.
253 /* .IP \fB-v\fR
254 /*	Enable verbose logging for debugging purposes. Multiple \fB-v\fR
255 /*	options make the software increasingly verbose.
256 /* DIAGNOSTICS
257 /*	Problems are reported to the standard error stream and to
258 /*	\fBsyslogd\fR(8) or \fBpostlogd\fR(8).
259 /*
260 /*	\fBpostsuper\fR(1) reports the number of messages deleted
261 /*	with \fB-d\fR, the number of messages expired with \fB-e\fR,
262 /*	the number of messages expired or released with \fB-f\fR,
263 /*	the number of messages held or released with \fB-h\fR or
264 /*	\fB-H\fR, the number of messages requeued with \fB-r\fR,
265 /*	and the number of messages whose queue file name was fixed
266 /*	with \fB-s\fR. The report is written to the standard error
267 /*	stream and to \fBsyslogd\fR(8) or \fBpostlogd\fR(8).
268 /* ENVIRONMENT
269 /* .ad
270 /* .fi
271 /* .IP MAIL_CONFIG
272 /*	Directory with the \fBmain.cf\fR file.
273 /* BUGS
274 /*	Mail that is not sanitized by Postfix (i.e. mail in the \fBmaildrop\fR
275 /*	queue) cannot be placed "on hold".
276 /* CONFIGURATION PARAMETERS
277 /* .ad
278 /* .fi
279 /*	The following \fBmain.cf\fR parameters are especially relevant to
280 /*	this program.
281 /*	The text below provides only a parameter summary. See
282 /*	\fBpostconf\fR(5) for more details including examples.
283 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
284 /*	The default location of the Postfix main.cf and master.cf
285 /*	configuration files.
286 /* .IP "\fBhash_queue_depth (1)\fR"
287 /*	The number of subdirectory levels for queue directories listed with
288 /*	the hash_queue_names parameter.
289 /* .IP "\fBhash_queue_names (deferred, defer)\fR"
290 /*	The names of queue directories that are split across multiple
291 /*	subdirectory levels.
292 /* .IP "\fBimport_environment (see 'postconf -d' output)\fR"
293 /*	The list of environment parameters that a privileged Postfix
294 /*	process will import from a non-Postfix parent process, or name=value
295 /*	environment overrides.
296 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
297 /*	The location of the Postfix top-level queue directory.
298 /* .IP "\fBsyslog_facility (mail)\fR"
299 /*	The syslog facility of Postfix logging.
300 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
301 /*	A prefix that is prepended to the process name in syslog
302 /*	records, so that, for example, "smtpd" becomes "prefix/smtpd".
303 /* .PP
304 /*	Available in Postfix version 2.9 and later:
305 /* .IP "\fBenable_long_queue_ids (no)\fR"
306 /*	Enable long, non-repeating, queue IDs (queue file names).
307 /* SEE ALSO
308 /*	sendmail(1), Sendmail-compatible user interface
309 /*	postqueue(1), unprivileged queue operations
310 /*	postlogd(8), Postfix logging
311 /*	syslogd(8), system logging
312 /* LICENSE
313 /* .ad
314 /* .fi
315 /*	The Secure Mailer license must be distributed with this software.
316 /* AUTHOR(S)
317 /*	Wietse Venema
318 /*	IBM T.J. Watson Research
319 /*	P.O. Box 704
320 /*	Yorktown Heights, NY 10598, USA
321 /*
322 /*	Wietse Venema
323 /*	Google, Inc.
324 /*	111 8th Avenue
325 /*	New York, NY 10011, USA
326 /*--*/
327 
328 /* System library. */
329 
330 #include <sys_defs.h>
331 #include <sys/stat.h>
332 #include <unistd.h>
333 #include <stdlib.h>
334 #include <errno.h>
335 #include <string.h>
336 #include <signal.h>
337 #include <stdio.h>			/* remove() */
338 #include <utime.h>
339 
340 /* Utility library. */
341 
342 #include <mymalloc.h>
343 #include <msg.h>
344 #include <vstream.h>
345 #include <msg_vstream.h>
346 #include <scan_dir.h>
347 #include <vstring.h>
348 #include <safe.h>
349 #include <set_ugid.h>
350 #include <argv.h>
351 #include <vstring_vstream.h>
352 #include <sane_fsops.h>
353 #include <myrand.h>
354 #include <warn_stat.h>
355 #include <clean_env.h>
356 #include <safe_open.h>
357 #include <name_mask.h>
358 
359 /* Global library. */
360 
361 #include <mail_task.h>
362 #include <mail_conf.h>
363 #include <mail_params.h>
364 #include <mail_version.h>
365 #define MAIL_QUEUE_INTERNAL
366 #include <mail_queue.h>
367 #include <mail_open_ok.h>
368 #include <file_id.h>
369 #include <mail_parm_split.h>
370 #include <maillog_client.h>
371 
372 /* Application-specific. */
373 
374 #define MAX_TEMP_AGE (7 * 60 * 60 * 24)	/* temp file maximal age */
375 #define STR vstring_str			/* silly little macro */
376 
377 #define ACTION_STRUCT	(1<<0)		/* fix file organization */
378 #define ACTION_PURGE	(1<<1)		/* purge old temp files */
379 #define ACTION_DELETE_ONE (1<<2)	/* delete named queue file(s) */
380 #define ACTION_DELETE_ALL (1<<3)	/* delete all queue file(s) */
381 #define ACTION_REQUEUE_ONE (1<<4)	/* requeue named queue file(s) */
382 #define ACTION_REQUEUE_ALL (1<<5)	/* requeue all queue file(s) */
383 #define ACTION_HOLD_ONE	(1<<6)		/* put named queue file(s) on hold */
384 #define ACTION_HOLD_ALL	(1<<7)		/* put all messages on hold */
385 #define ACTION_RELEASE_ONE (1<<8)	/* release named queue file(s) */
386 #define ACTION_RELEASE_ALL (1<<9)	/* release all "on hold" mail */
387 #define ACTION_STRUCT_RED (1<<10)	/* fix long queue ID inode fields */
388 #define ACTION_EXPIRE_ONE (1<<11)	/* expire named queue file(s) */
389 #define ACTION_EXPIRE_ALL (1<<12)	/* expire all queue file(s) */
390 #define ACTION_EXP_REL_ONE (1<<13)	/* expire+release named queue file(s) */
391 #define ACTION_EXP_REL_ALL (1<<14)	/* expire+release all queue file(s) */
392 
393 #define ACTION_DEFAULT	(ACTION_STRUCT | ACTION_PURGE)
394 
395  /*
396   * Actions that operate on individually named queue files. These must never
397   * be done after fixing queue file names to match their inode number because
398   * the target file may have been replaced. Actions that move files are safe
399   * only when queue file names match their inode number, otherwise mail can
400   * be lost due to filename collisions.
401   */
402 #define ACTIONS_BY_QUEUE_ID	(ACTION_DELETE_ONE | ACTION_REQUEUE_ONE \
403 				| ACTION_HOLD_ONE | ACTION_RELEASE_ONE \
404 				| ACTION_EXPIRE_ONE | ACTION_EXP_REL_ONE)
405 
406  /*
407   * Mass actions. Actions that move files are safe only when queue file names
408   * match their inode number, otherwise mail can be lost due to filename
409   * collisions.
410   */
411 #define ACTIONS_BY_WILDCARD	(ACTION_DELETE_ALL | ACTION_REQUEUE_ALL \
412 				| ACTION_HOLD_ALL | ACTION_RELEASE_ALL \
413 				| ACTION_EXPIRE_ALL | ACTION_EXP_REL_ALL)
414 
415 #define ACTIONS_FOR_REPAIR	(ACTION_PURGE | ACTION_STRUCT \
416 				| ACTION_STRUCT_RED)
417 
418  /*
419   * Information about queue directories and what we expect to do there. If a
420   * file has unexpected owner permissions and is older than some threshold,
421   * the file is discarded. We don't step into maildrop subdirectories - if
422   * maildrop is writable, we might end up in the wrong place, deleting the
423   * wrong information.
424   */
425 struct queue_info {
426     char   *name;			/* directory name */
427     int     perms;			/* expected permissions */
428     int     flags;			/* see below */
429 };
430 
431 #define RECURSE		(1<<0)		/* step into subdirectories */
432 #define	DONT_RECURSE	0		/* don't step into directories */
433 
434 static struct queue_info queue_info[] = {
435     MAIL_QUEUE_MAILDROP, MAIL_QUEUE_STAT_READY, DONT_RECURSE,
436     MAIL_QUEUE_INCOMING, MAIL_QUEUE_STAT_READY, RECURSE,
437     MAIL_QUEUE_ACTIVE, MAIL_QUEUE_STAT_READY, RECURSE,
438     MAIL_QUEUE_DEFERRED, MAIL_QUEUE_STAT_READY, RECURSE,
439     MAIL_QUEUE_HOLD, MAIL_QUEUE_STAT_READY, RECURSE,
440     MAIL_QUEUE_TRACE, 0600, RECURSE,
441     MAIL_QUEUE_DEFER, 0600, RECURSE,
442     MAIL_QUEUE_BOUNCE, 0600, RECURSE,
443     MAIL_QUEUE_FLUSH, 0600, RECURSE,
444     0,
445 };
446 
447  /*
448   * Directories with per-message meta files.
449   */
450 const char *log_queue_names[] = {
451     MAIL_QUEUE_BOUNCE,
452     MAIL_QUEUE_DEFER,
453     MAIL_QUEUE_TRACE,
454     0,
455 };
456 
457  /*
458   * Cruft that we append to a file name when a queue ID is named after the
459   * message file inode number. This cruft must not pass mail_queue_id_ok() so
460   * that the queue manager will ignore it, should people be so unwise as to
461   * run this operation on a live mail system.
462   */
463 #define SUFFIX		"#FIX"
464 #define SUFFIX_LEN	4
465 
466  /*
467   * Grr. These counters are global, because C only has clumsy ways to return
468   * multiple results from a function.
469   */
470 static int message_requeued = 0;	/* requeued messages */
471 static int message_held = 0;		/* messages put on hold */
472 static int message_released = 0;	/* messages released from hold */
473 static int message_deleted = 0;		/* deleted messages */
474 static int message_expired = 0;		/* expired messages */
475 static int inode_fixed = 0;		/* queue id matched to inode number */
476 static int inode_mismatch = 0;		/* queue id inode mismatch */
477 static int position_mismatch = 0;	/* file position mismatch */
478 
479  /*
480   * Silly little macros. These translate arcane expressions into something
481   * more at a conceptual level.
482   */
483 #define MESSAGE_QUEUE(qp) ((qp)->perms == MAIL_QUEUE_STAT_READY)
484 #define READY_MESSAGE(st) (((st).st_mode & S_IRWXU) == MAIL_QUEUE_STAT_READY)
485 
486 /* find_queue_info - look up expected permissions field by queue name */
487 
find_queue_info(const char * queue_name)488 static struct queue_info *find_queue_info(const char *queue_name)
489 {
490     struct queue_info *qp;
491 
492     for (qp = queue_info; qp->name; qp++)
493 	if (strcmp(queue_name, qp->name) == 0)
494 	    return (qp);
495     msg_fatal("invalid directory name: %s", queue_name);
496 }
497 
498 /* postremove - remove file with extreme prejudice */
499 
postremove(const char * path)500 static int postremove(const char *path)
501 {
502     int     ret;
503 
504     if ((ret = remove(path)) < 0) {
505 	if (errno != ENOENT)
506 	    msg_fatal("remove file %s: %m", path);
507     } else {
508 	if (msg_verbose)
509 	    msg_info("removed file %s", path);
510     }
511     return (ret);
512 }
513 
514 /* postexpire - expire file, setting the group execute permission */
515 
postexpire(const char * path)516 static int postexpire(const char *path)
517 {
518     static VSTRING *why = 0;
519     VSTREAM *fp;
520     struct stat st;
521 
522     /*
523      * Initialize.
524      */
525     if (why == 0)
526 	why = vstring_alloc(100);
527 
528     /*
529      * We don't actually verify the file content, therefore safe_open() the
530      * queue file so that we won't add group execute permission to some file
531      * outside of the mail queue.
532      */
533     if ((fp = safe_open(path, O_RDWR, 0, &st, -1, -1, why)) == 0) {
534 	if (errno != ENOENT)
535 	    msg_warn("expire file %s: %s", path, vstring_str(why));
536 	return (-1);
537     }
538 #define POSTEXPIRE_RETURN(x) do { \
539 	(void) vstream_fclose(fp); \
540 	return (x); \
541     } while (0)
542 
543     if (!READY_MESSAGE(st))
544 	POSTEXPIRE_RETURN(-1);			/* must not expire */
545     if ((st.st_mode & MAIL_QUEUE_STAT_EXPIRE) != 0)
546 	POSTEXPIRE_RETURN(-1);			/* already expired */
547     if (fchmod(vstream_fileno(fp),
548 	       (st.st_mode | MAIL_QUEUE_STAT_EXPIRE) & ~S_IFMT) < 0) {
549 	msg_warn("expire file %s: cannot set permission: %m", path);
550 	POSTEXPIRE_RETURN(-1);
551     }
552     POSTEXPIRE_RETURN(0);
553 }
554 
555 /* postrename - rename file with extreme prejudice */
556 
postrename(const char * old,const char * new)557 static int postrename(const char *old, const char *new)
558 {
559     int     ret;
560 
561     if ((ret = sane_rename(old, new)) < 0) {
562 	if (errno != ENOENT
563 	    || mail_queue_mkdirs(new) < 0
564 	    || (ret = sane_rename(old, new)) < 0)
565 	    if (errno != ENOENT)
566 		msg_fatal("rename file %s as %s: %m", old, new);
567     } else {
568 	if (msg_verbose)
569 	    msg_info("renamed file %s as %s", old, new);
570     }
571     return (ret);
572 }
573 
574 /* postrmdir - remove directory with extreme prejudice */
575 
postrmdir(const char * path)576 static int postrmdir(const char *path)
577 {
578     int     ret;
579 
580     if ((ret = rmdir(path)) < 0) {
581 	if (errno != ENOENT)
582 	    msg_fatal("remove directory %s: %m", path);
583     } else {
584 	if (msg_verbose)
585 	    msg_info("remove directory %s", path);
586     }
587     return (ret);
588 }
589 
590 /* delete_one - delete one message instance and all its associated files */
591 
delete_one(const char ** queue_names,const char * queue_id)592 static void delete_one(const char **queue_names, const char *queue_id)
593 {
594     struct stat st;
595     const char **msg_qpp;
596     const char **log_qpp;
597     const char *msg_path;
598     VSTRING *log_path_buf;
599     int     found;
600     int     tries;
601 
602     /*
603      * Sanity check. No early returns beyond this point.
604      */
605     if (!mail_queue_id_ok(queue_id)) {
606 	msg_warn("invalid mail queue id: %s", queue_id);
607 	return;
608     }
609     log_path_buf = vstring_alloc(100);
610 
611     /*
612      * Skip meta file directories. Delete trace/defer/bounce logfiles before
613      * deleting the corresponding message file, and only if the message file
614      * exists. This minimizes but does not eliminate a race condition with
615      * queue ID reuse which results in deleting the wrong files.
616      */
617     for (found = 0, tries = 0; found == 0 && tries < 2; tries++) {
618 	for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
619 	    if (!MESSAGE_QUEUE(find_queue_info(*msg_qpp)))
620 		continue;
621 	    if (mail_open_ok(*msg_qpp, queue_id, &st, &msg_path) != MAIL_OPEN_YES)
622 		continue;
623 	    for (log_qpp = log_queue_names; *log_qpp != 0; log_qpp++)
624 		postremove(mail_queue_path(log_path_buf, *log_qpp, queue_id));
625 	    if (postremove(msg_path) == 0) {
626 		found = 1;
627 		msg_info("%s: removed", queue_id);
628 		break;
629 	    }					/* else: maybe lost a race */
630 	}
631     }
632     vstring_free(log_path_buf);
633     message_deleted += found;
634 }
635 
636 /* requeue_one - requeue one message instance and delete its logfiles */
637 
requeue_one(const char ** queue_names,const char * queue_id)638 static void requeue_one(const char **queue_names, const char *queue_id)
639 {
640     struct stat st;
641     const char **msg_qpp;
642     const char *old_path;
643     VSTRING *new_path_buf;
644     int     found;
645     int     tries;
646     struct utimbuf tbuf;
647 
648     /*
649      * Sanity check. No early returns beyond this point.
650      */
651     if (!mail_queue_id_ok(queue_id)) {
652 	msg_warn("invalid mail queue id: %s", queue_id);
653 	return;
654     }
655     new_path_buf = vstring_alloc(100);
656 
657     /*
658      * Skip meta file directories. Like the mass requeue operation, we not
659      * delete defer or bounce logfiles, to avoid losing a race where the
660      * queue manager decides to bounce mail after all recipients have been
661      * tried.
662      */
663     for (found = 0, tries = 0; found == 0 && tries < 2; tries++) {
664 	for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
665 	    if (strcmp(*msg_qpp, MAIL_QUEUE_MAILDROP) == 0)
666 		continue;
667 	    if (!MESSAGE_QUEUE(find_queue_info(*msg_qpp)))
668 		continue;
669 	    if (mail_open_ok(*msg_qpp, queue_id, &st, &old_path) != MAIL_OPEN_YES)
670 		continue;
671 	    (void) mail_queue_path(new_path_buf, MAIL_QUEUE_MAILDROP, queue_id);
672 	    if (postrename(old_path, STR(new_path_buf)) == 0) {
673 		tbuf.actime = tbuf.modtime = time((time_t *) 0);
674 		if (utime(STR(new_path_buf), &tbuf) < 0)
675 		    msg_warn("%s: reset time stamps: %m", STR(new_path_buf));
676 		msg_info("%s: requeued", queue_id);
677 		found = 1;
678 		break;
679 	    }					/* else: maybe lost a race */
680 	}
681     }
682     vstring_free(new_path_buf);
683     message_requeued += found;
684 }
685 
686 /* hold_one - put "on hold" one message instance */
687 
hold_one(const char ** queue_names,const char * queue_id)688 static void hold_one(const char **queue_names, const char *queue_id)
689 {
690     struct stat st;
691     const char **msg_qpp;
692     const char *old_path;
693     VSTRING *new_path_buf;
694     int     found;
695     int     tries;
696 
697     /*
698      * Sanity check. No early returns beyond this point.
699      */
700     if (!mail_queue_id_ok(queue_id)) {
701 	msg_warn("invalid mail queue id: %s", queue_id);
702 	return;
703     }
704     new_path_buf = vstring_alloc(100);
705 
706     /*
707      * Skip meta file directories. Like the mass requeue operation, we not
708      * delete defer or bounce logfiles, to avoid losing a race where the
709      * queue manager decides to bounce mail after all recipients have been
710      * tried.
711      *
712      * XXX We must not put maildrop mail on hold because that would mix already
713      * sanitized mail with mail that still needs to be sanitized.
714      */
715     for (found = 0, tries = 0; found == 0 && tries < 2; tries++) {
716 	for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
717 	    if (strcmp(*msg_qpp, MAIL_QUEUE_MAILDROP) == 0)
718 		continue;
719 	    if (strcmp(*msg_qpp, MAIL_QUEUE_HOLD) == 0)
720 		continue;
721 	    if (!MESSAGE_QUEUE(find_queue_info(*msg_qpp)))
722 		continue;
723 	    if (mail_open_ok(*msg_qpp, queue_id, &st, &old_path) != MAIL_OPEN_YES)
724 		continue;
725 	    (void) mail_queue_path(new_path_buf, MAIL_QUEUE_HOLD, queue_id);
726 	    if (postrename(old_path, STR(new_path_buf)) == 0) {
727 		msg_info("%s: placed on hold", queue_id);
728 		found = 1;
729 		break;
730 	    }					/* else: maybe lost a race */
731 	}
732     }
733     vstring_free(new_path_buf);
734     message_held += found;
735 }
736 
737 /* release_one - release one message instance that was placed "on hold" */
738 
release_one(const char ** queue_names,const char * queue_id)739 static void release_one(const char **queue_names, const char *queue_id)
740 {
741     struct stat st;
742     const char **msg_qpp;
743     const char *old_path;
744     VSTRING *new_path_buf;
745     int     found;
746 
747     /*
748      * Sanity check. No early returns beyond this point.
749      */
750     if (!mail_queue_id_ok(queue_id)) {
751 	msg_warn("invalid mail queue id: %s", queue_id);
752 	return;
753     }
754     new_path_buf = vstring_alloc(100);
755 
756     /*
757      * Skip inapplicable directories. This can happen when -H is combined
758      * with other operations.
759      */
760     found = 0;
761     for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
762 	if (strcmp(*msg_qpp, MAIL_QUEUE_HOLD) != 0)
763 	    continue;
764 	if (mail_open_ok(*msg_qpp, queue_id, &st, &old_path) != MAIL_OPEN_YES)
765 	    continue;
766 	(void) mail_queue_path(new_path_buf, MAIL_QUEUE_DEFERRED, queue_id);
767 	if (postrename(old_path, STR(new_path_buf)) == 0) {
768 	    msg_info("%s: released from hold", queue_id);
769 	    found = 1;
770 	    break;
771 	}
772     }
773     vstring_free(new_path_buf);
774     message_released += found;
775 }
776 
777 /* expire_one - expire one message instance */
778 
expire_one(const char ** queue_names,const char * queue_id)779 static void expire_one(const char **queue_names, const char *queue_id)
780 {
781     struct stat st;
782     const char **msg_qpp;
783     const char *msg_path;
784     int     found;
785     int     tries;
786 
787     /*
788      * Sanity check. No early returns beyond this point.
789      */
790     if (!mail_queue_id_ok(queue_id)) {
791 	msg_warn("invalid mail queue id: %s", queue_id);
792 	return;
793     }
794 
795     /*
796      * Skip meta file directories.
797      */
798     for (found = 0, tries = 0; found == 0 && tries < 2; tries++) {
799 	for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
800 	    if (!MESSAGE_QUEUE(find_queue_info(*msg_qpp)))
801 		continue;
802 	    if (strcmp(*msg_qpp, MAIL_QUEUE_MAILDROP) == 0)
803 		continue;
804 	    if (mail_open_ok(*msg_qpp, queue_id, &st, &msg_path) != MAIL_OPEN_YES)
805 		continue;
806 	    if (postexpire(msg_path) == 0) {
807 		found = 1;
808 		msg_info("%s: expired", queue_id);
809 		break;
810 	    }					/* else: maybe lost a race */
811 	}
812     }
813     message_expired += found;
814 }
815 
816 /* exp_rel_one - expire or release one message instance */
817 
exp_rel_one(const char ** queue_names,const char * queue_id)818 static void exp_rel_one(const char **queue_names, const char *queue_id)
819 {
820     expire_one(queue_names, queue_id);
821     release_one(queue_names, queue_id);
822 }
823 
824 /* operate_stream - operate on queue IDs given on stream */
825 
operate_stream(VSTREAM * fp,void (* operator)(const char **,const char *),const char ** queues)826 static void operate_stream(VSTREAM *fp,
827 		             void (*operator) (const char **, const char *),
828 			           const char **queues)
829 {
830     VSTRING *buf = vstring_alloc(20);
831 
832     while (vstring_get_nonl(buf, fp) != VSTREAM_EOF)
833 	operator(queues, STR(buf));
834 
835     vstring_free(buf);
836 }
837 
838 /* fix_queue_id - make message queue ID match inode number */
839 
fix_queue_id(const char * actual_path,const char * actual_queue,const char * actual_id,struct stat * st)840 static int fix_queue_id(const char *actual_path, const char *actual_queue,
841 			        const char *actual_id, struct stat * st)
842 {
843     VSTRING *old_path = vstring_alloc(10);
844     VSTRING *new_path = vstring_alloc(10);
845     VSTRING *new_id = vstring_alloc(10);
846     const char **log_qpp;
847     char   *cp;
848     int     ret;
849 
850     /*
851      * Create the new queue ID from the existing time digits and from the new
852      * inode number. Since we are renaming multiple files, the new name must
853      * be deterministic so that we can recover even when the renaming
854      * operation is interrupted in the middle.
855      */
856     if (MQID_FIND_LG_INUM_SEPARATOR(cp, actual_id) == 0) {
857 	/* Short->short queue ID. Replace the inode portion. */
858 	vstring_sprintf(new_id, "%.*s%s",
859 			MQID_SH_USEC_PAD, actual_id,
860 			get_file_id_st(st, 0));
861     } else if (var_long_queue_ids) {
862 	/* Long->long queue ID. Replace the inode portion. */
863 	vstring_sprintf(new_id, "%.*s%c%s",
864 			(int) (cp - actual_id), actual_id, MQID_LG_INUM_SEP,
865 			get_file_id_st(st, 1));
866     } else {
867 	/* Long->short queue ID. Reformat time and replace inode portion. */
868 	MQID_LG_GET_HEX_USEC(new_id, cp);
869 	vstring_strcat(new_id, get_file_id_st(st, 0));
870     }
871 
872     /*
873      * Rename logfiles before renaming the message file, so that we can
874      * recover when a previous attempt was interrupted.
875      */
876     for (log_qpp = log_queue_names; *log_qpp; log_qpp++) {
877 	mail_queue_path(old_path, *log_qpp, actual_id);
878 	mail_queue_path(new_path, *log_qpp, STR(new_id));
879 	vstring_strcat(new_path, SUFFIX);
880 	postrename(STR(old_path), STR(new_path));
881     }
882 
883     /*
884      * Rename the message file last, so that we know that we are done with
885      * this message and with all its logfiles.
886      */
887     mail_queue_path(new_path, actual_queue, STR(new_id));
888     vstring_strcat(new_path, SUFFIX);
889     ret = postrename(actual_path, STR(new_path));
890 
891     /*
892      * Clean up.
893      */
894     vstring_free(old_path);
895     vstring_free(new_path);
896     vstring_free(new_id);
897 
898     return (ret);
899 }
900 
901 /* super - check queue structure, clean up, do wild-card operations */
902 
super(const char ** queues,int action)903 static void super(const char **queues, int action)
904 {
905     ARGV   *hash_queue_names = argv_split(var_hash_queue_names, CHARS_COMMA_SP);
906     VSTRING *actual_path = vstring_alloc(10);
907     VSTRING *wanted_path = vstring_alloc(10);
908     struct stat st;
909     const char *queue_name;
910     SCAN_DIR *info;
911     char   *path;
912     int     actual_depth;
913     int     wanted_depth;
914     char  **cpp;
915     struct queue_info *qp;
916     unsigned long inum;
917     int     long_name;
918     int     error;
919 
920     /*
921      * This routine was originally written to do multiple mass operations in
922      * one pass. However this hard-coded the order of operations which became
923      * difficult to explain. As of Postfix 3.5 this routine is called for one
924      * mass operation at a time, in the user-specified order. The exception
925      * is that repair operations (purging stale files, queue hashing, and
926      * file-inode match) are combined and done before other mass operations.
927      */
928 
929     /*
930      * Make sure every file is in the right place, clean out stale files, and
931      * remove non-file/non-directory objects.
932      */
933     while ((queue_name = *queues++) != 0) {
934 
935 	if (msg_verbose)
936 	    msg_info("queue: %s", queue_name);
937 
938 	/*
939 	 * Look up queue-specific properties: desired hashing depth, what
940 	 * file permissions to look for, and whether or not it is desirable
941 	 * to step into subdirectories.
942 	 */
943 	qp = find_queue_info(queue_name);
944 	for (cpp = hash_queue_names->argv; /* void */ ; cpp++) {
945 	    if (*cpp == 0) {
946 		wanted_depth = 0;
947 		break;
948 	    }
949 	    if (strcmp(*cpp, queue_name) == 0) {
950 		wanted_depth = var_hash_queue_depth;
951 		break;
952 	    }
953 	}
954 
955 	/*
956 	 * Sanity check. Some queues just cannot be recursive.
957 	 */
958 	if (wanted_depth > 0 && (qp->flags & RECURSE) == 0)
959 	    msg_fatal("%s queue must not be hashed", queue_name);
960 
961 	/*
962 	 * Other per-directory initialization.
963 	 */
964 	info = scan_dir_open(queue_name);
965 	actual_depth = 0;
966 
967 	for (;;) {
968 
969 	    /*
970 	     * If we reach the end of a subdirectory, return to its parent.
971 	     * Delete subdirectories that are no longer needed.
972 	     */
973 	    if ((path = scan_dir_next(info)) == 0) {
974 		if (actual_depth == 0)
975 		    break;
976 		if (actual_depth > wanted_depth)
977 		    postrmdir(scan_dir_path(info));
978 		scan_dir_pop(info);
979 		actual_depth--;
980 		continue;
981 	    }
982 
983 	    /*
984 	     * If we stumble upon a subdirectory, enter it, if it is
985 	     * considered safe to do so. Otherwise, try to remove the
986 	     * subdirectory at a later stage.
987 	     */
988 	    if (strlen(path) == 1 && (qp->flags & RECURSE) != 0) {
989 		actual_depth++;
990 		scan_dir_push(info, path);
991 		continue;
992 	    }
993 
994 	    /*
995 	     * From here on we need to keep track of operations that
996 	     * invalidate or revalidate the actual_path and path variables,
997 	     * otherwise we can hit the wrong files.
998 	     */
999 	    vstring_sprintf(actual_path, "%s/%s", scan_dir_path(info), path);
1000 	    if (lstat(STR(actual_path), &st) < 0)
1001 		continue;
1002 
1003 	    /*
1004 	     * Remove alien directories. If maildrop is compromised, then we
1005 	     * cannot abort just because we cannot remove someone's
1006 	     * directory.
1007 	     */
1008 	    if (S_ISDIR(st.st_mode)) {
1009 		if (rmdir(STR(actual_path)) < 0) {
1010 		    if (errno != ENOENT)
1011 			msg_warn("remove subdirectory %s: %m", STR(actual_path));
1012 		} else {
1013 		    if (msg_verbose)
1014 			msg_info("remove subdirectory %s", STR(actual_path));
1015 		}
1016 		/* No further work on this object is possible. */
1017 		continue;
1018 	    }
1019 
1020 	    /*
1021 	     * Mass deletion. We count the deletion of mail that this system
1022 	     * has taken responsibility for. XXX This option does not use
1023 	     * mail_queue_remove(), so that it can avoid having to first move
1024 	     * queue files to the "right" subdirectory level.
1025 	     */
1026 	    if (action & ACTION_DELETE_ALL) {
1027 		if (postremove(STR(actual_path)) == 0)
1028 		    if (MESSAGE_QUEUE(qp) && READY_MESSAGE(st))
1029 			message_deleted++;
1030 		/* No further work on this object is possible. */
1031 		continue;
1032 	    }
1033 
1034 	    /*
1035 	     * Remove non-file objects and old temporary files. Be careful
1036 	     * not to delete bounce or defer logs just because they are more
1037 	     * than a couple days old.
1038 	     */
1039 	    if (!S_ISREG(st.st_mode)
1040 		|| ((action & ACTION_PURGE) != 0
1041 		    && MESSAGE_QUEUE(qp)
1042 		    && !READY_MESSAGE(st)
1043 		    && time((time_t *) 0) > st.st_mtime + MAX_TEMP_AGE)) {
1044 		(void) postremove(STR(actual_path));
1045 		/* No further work on this object is possible. */
1046 		continue;
1047 	    }
1048 
1049 	    /*
1050 	     * Fix queueid#FIX names that were left from a previous pass over
1051 	     * the queue where message queue file names were matched to their
1052 	     * inode number. We strip the suffix and move the file into the
1053 	     * proper subdirectory level. Make sure that the name minus
1054 	     * suffix is well formed and that the name matches the file inode
1055 	     * number.
1056 	     */
1057 	    if ((action & ACTION_STRUCT)
1058 		&& strcmp(path + (strlen(path) - SUFFIX_LEN), SUFFIX) == 0) {
1059 		path[strlen(path) - SUFFIX_LEN] = 0;	/* XXX */
1060 		if (!mail_queue_id_ok(path)) {
1061 		    msg_warn("bogus file name: %s", STR(actual_path));
1062 		    continue;
1063 		}
1064 		if (MESSAGE_QUEUE(qp)) {
1065 		    MQID_GET_INUM(path, inum, long_name, error);
1066 		    if (error) {
1067 			msg_warn("bogus file name: %s", STR(actual_path));
1068 			continue;
1069 		    }
1070 		    if (inum != (unsigned long) st.st_ino) {
1071 			msg_warn("name/inode mismatch: %s", STR(actual_path));
1072 			continue;
1073 		    }
1074 		}
1075 		(void) mail_queue_path(wanted_path, queue_name, path);
1076 		if (postrename(STR(actual_path), STR(wanted_path)) < 0) {
1077 		    /* No further work on this object is possible. */
1078 		    continue;
1079 		} else {
1080 		    if (MESSAGE_QUEUE(qp))
1081 			inode_fixed++;
1082 		    vstring_strcpy(actual_path, STR(wanted_path));
1083 		    /* At this point, path and actual_path are revalidated. */
1084 		}
1085 	    }
1086 
1087 	    /*
1088 	     * Skip over files with illegal names. The library routines
1089 	     * refuse to operate on them.
1090 	     */
1091 	    if (!mail_queue_id_ok(path)) {
1092 		msg_warn("bogus file name: %s", STR(actual_path));
1093 		continue;
1094 	    }
1095 
1096 	    /*
1097 	     * See if the file name matches the file inode number. Skip meta
1098 	     * file directories. This option requires that meta files be put
1099 	     * into their proper place before queue files, so that we can
1100 	     * rename queue files and meta files at the same time. Mis-named
1101 	     * files are renamed to newqueueid#FIX on the first pass, and
1102 	     * upon the second pass the #FIX is stripped off the name. Of
1103 	     * course we have to be prepared that the program is interrupted
1104 	     * before it completes, so any left-over newqueueid#FIX files
1105 	     * have to be handled properly. XXX This option cannot use
1106 	     * mail_queue_rename(), because the queue file name violates
1107 	     * normal queue file syntax.
1108 	     *
1109 	     * By design there is no need to "fix" non-repeating names. What
1110 	     * follows is applicable only when reverting from long names to
1111 	     * short names, or when migrating short names from one queue to
1112 	     * another.
1113 	     */
1114 	    if ((action & ACTION_STRUCT) != 0 && MESSAGE_QUEUE(qp)) {
1115 		MQID_GET_INUM(path, inum, long_name, error);
1116 		if (error) {
1117 		    msg_warn("bogus file name: %s", STR(actual_path));
1118 		    continue;
1119 		}
1120 		if ((long_name != 0 && var_long_queue_ids == 0)
1121 		    || (inum != (unsigned long) st.st_ino
1122 		     && (long_name == 0 || (action & ACTION_STRUCT_RED)))) {
1123 		    inode_mismatch++;		/* before we fix */
1124 		    action &= ~ACTIONS_BY_WILDCARD;
1125 		    fix_queue_id(STR(actual_path), queue_name, path, &st);
1126 		    /* At this point, path and actual_path are invalidated. */
1127 		    continue;
1128 		}
1129 	    }
1130 
1131 	    /*
1132 	     * Mass requeuing. The pickup daemon will copy requeued mail to a
1133 	     * new queue file, so that address rewriting is applied again.
1134 	     * XXX This option does not use mail_queue_rename(), so that it
1135 	     * can avoid having to first move queue files to the "right"
1136 	     * subdirectory level. Like the requeue_one() routine, this code
1137 	     * does not touch logfiles.
1138 	     */
1139 	    if ((action & ACTION_REQUEUE_ALL)
1140 		&& MESSAGE_QUEUE(qp)
1141 		&& strcmp(queue_name, MAIL_QUEUE_MAILDROP) != 0) {
1142 		(void) mail_queue_path(wanted_path, MAIL_QUEUE_MAILDROP, path);
1143 		if (postrename(STR(actual_path), STR(wanted_path)) == 0)
1144 		    message_requeued++;
1145 		/* At this point, path and actual_path are invalidated. */
1146 		continue;
1147 	    }
1148 
1149 	    /*
1150 	     * Many of the following actions may move queue files. To avoid
1151 	     * loss of email due to file name collisions. we should do such
1152 	     * actions only when the queue file names are known to match
1153 	     * their inode number. Even with non-repeating queue IDs a name
1154 	     * collision may happen when different queues are merged.
1155 	     */
1156 
1157 	    /*
1158 	     * Mass expiration. We count the expiration of mail that this
1159 	     * system has taken responsibility for.
1160 	     */
1161 	    if ((action & (ACTION_EXPIRE_ALL | ACTION_EXP_REL_ALL))
1162 		&& MESSAGE_QUEUE(qp) && READY_MESSAGE(st)
1163 		&& strcmp(queue_name, MAIL_QUEUE_MAILDROP) != 0
1164 		&& postexpire(STR(actual_path)) == 0)
1165 		message_expired++;
1166 
1167 	    /*
1168 	     * Mass renaming to the "on hold" queue. XXX This option does not
1169 	     * use mail_queue_rename(), so that it can avoid having to first
1170 	     * move queue files to the "right" subdirectory level. Like the
1171 	     * hold_one() routine, this code does not touch logfiles, and
1172 	     * must not touch files in the maildrop queue, because maildrop
1173 	     * files contain data that has not yet been sanitized and
1174 	     * therefore must not be mixed with already sanitized mail.
1175 	     */
1176 	    if ((action & ACTION_HOLD_ALL)
1177 		&& MESSAGE_QUEUE(qp)
1178 		&& strcmp(queue_name, MAIL_QUEUE_MAILDROP) != 0
1179 		&& strcmp(queue_name, MAIL_QUEUE_HOLD) != 0) {
1180 		(void) mail_queue_path(wanted_path, MAIL_QUEUE_HOLD, path);
1181 		if (postrename(STR(actual_path), STR(wanted_path)) == 0)
1182 		    message_held++;
1183 		/* At this point, path and actual_path are invalidated. */
1184 		continue;
1185 	    }
1186 
1187 	    /*
1188 	     * Mass release from the "on hold" queue. XXX This option does
1189 	     * not use mail_queue_rename(), so that it can avoid having to
1190 	     * first move queue files to the "right" subdirectory level. Like
1191 	     * the release_one() routine, this code must not touch logfiles.
1192 	     */
1193 	    if ((action & (ACTION_RELEASE_ALL | ACTION_EXP_REL_ALL))
1194 		&& strcmp(queue_name, MAIL_QUEUE_HOLD) == 0) {
1195 		(void) mail_queue_path(wanted_path, MAIL_QUEUE_DEFERRED, path);
1196 		if (postrename(STR(actual_path), STR(wanted_path)) == 0)
1197 		    message_released++;
1198 		/* At this point, path and actual_path are invalidated. */
1199 		continue;
1200 	    }
1201 
1202 	    /*
1203 	     * See if this file sits in the right place in the file system
1204 	     * hierarchy. Its place may be wrong after a change to the
1205 	     * hash_queue_{names,depth} parameter settings. This requires
1206 	     * that the bounce/defer logfiles be at the right subdirectory
1207 	     * level first, otherwise we would fail to properly rename
1208 	     * bounce/defer logfiles.
1209 	     */
1210 	    if (action & ACTION_STRUCT) {
1211 		(void) mail_queue_path(wanted_path, queue_name, path);
1212 		if (strcmp(STR(actual_path), STR(wanted_path)) != 0) {
1213 		    position_mismatch++;	/* before we fix */
1214 		    (void) postrename(STR(actual_path), STR(wanted_path));
1215 		    /* At this point, path and actual_path are invalidated. */
1216 		    continue;
1217 		}
1218 	    }
1219 	}
1220 	scan_dir_close(info);
1221     }
1222 
1223     /*
1224      * Clean up.
1225      */
1226     vstring_free(wanted_path);
1227     vstring_free(actual_path);
1228     argv_free(hash_queue_names);
1229 }
1230 
1231 /* interrupted - signal handler */
1232 
interrupted(int sig)1233 static void interrupted(int sig)
1234 {
1235 
1236     /*
1237      * This commands requires root privileges. We therefore do not worry
1238      * about hostile signals, and report problems via msg_warn().
1239      *
1240      * We use the in-kernel SIGINT handler address as an atomic variable to
1241      * prevent nested interrupted() calls. For this reason, main() must
1242      * configure interrupted() as SIGINT handler before other signal handlers
1243      * are allowed to invoke interrupted(). See also similar code in
1244      * postdrop.
1245      */
1246     if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
1247 	(void) signal(SIGQUIT, SIG_IGN);
1248 	(void) signal(SIGTERM, SIG_IGN);
1249 	(void) signal(SIGHUP, SIG_IGN);
1250 	if (inode_mismatch > 0 || inode_fixed > 0 || position_mismatch > 0)
1251 	    msg_warn("OPERATION INCOMPLETE -- RERUN COMMAND TO FIX THE QUEUE FIRST");
1252 	if (sig)
1253 	    _exit(sig);
1254     }
1255 }
1256 
1257 /* fatal_warning - print warning if queue fix is incomplete */
1258 
fatal_warning(void)1259 static void fatal_warning(void)
1260 {
1261     interrupted(0);
1262 }
1263 
1264 MAIL_VERSION_STAMP_DECLARE;
1265 
main(int argc,char ** argv)1266 int     main(int argc, char **argv)
1267 {
1268     int     fd;
1269     struct stat st;
1270     char   *slash;
1271     int     action = 0;
1272     const char **queues;
1273     int     c;
1274     ARGV   *import_env;
1275     int     saved_optind;
1276 
1277     /*
1278      * Defaults. The structural checks must fix the directory levels of "log
1279      * file" directories (bounce, defer) before doing structural checks on
1280      * the "message file" directories, so that we can find the logfiles in
1281      * the right place when message files need to be renamed to match their
1282      * inode number.
1283      */
1284     static char *default_queues[] = {
1285 	MAIL_QUEUE_DEFER,		/* before message directories */
1286 	MAIL_QUEUE_BOUNCE,		/* before message directories */
1287 	MAIL_QUEUE_MAILDROP,
1288 	MAIL_QUEUE_INCOMING,
1289 	MAIL_QUEUE_ACTIVE,
1290 	MAIL_QUEUE_DEFERRED,
1291 	MAIL_QUEUE_HOLD,
1292 	MAIL_QUEUE_FLUSH,
1293 	0,
1294     };
1295 
1296     /*
1297      * Fingerprint executables and core dumps.
1298      */
1299     MAIL_VERSION_STAMP_ALLOCATE;
1300 
1301     /*
1302      * Be consistent with file permissions.
1303      */
1304     umask(022);
1305 
1306     /*
1307      * To minimize confusion, make sure that the standard file descriptors
1308      * are open before opening anything else. XXX Work around for 44BSD where
1309      * fstat can return EBADF on an open file descriptor.
1310      */
1311     for (fd = 0; fd < 3; fd++)
1312 	if (fstat(fd, &st) == -1
1313 	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
1314 	    msg_fatal("open /dev/null: %m");
1315 
1316     /*
1317      * Process this environment option as early as we can, to aid debugging.
1318      */
1319     if (safe_getenv(CONF_ENV_VERB))
1320 	msg_verbose = 1;
1321 
1322     /*
1323      * Initialize logging.
1324      */
1325     if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
1326 	argv[0] = slash + 1;
1327     msg_vstream_init(argv[0], VSTREAM_ERR);
1328     maillog_client_init(mail_task(argv[0]),
1329 			MAILLOG_CLIENT_FLAG_LOGWRITER_FALLBACK);
1330     set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
1331 
1332     /*
1333      * Check the Postfix library version as soon as we enable logging.
1334      */
1335     MAIL_VERSION_CHECK;
1336 
1337     /*
1338      * Disallow unsafe practices, and refuse to run set-uid (or as the child
1339      * of a set-uid process). Whenever a privileged wrapper program is
1340      * needed, it must properly sanitize the real/effective/saved UID/GID,
1341      * the secondary groups, the process environment, and so on. Otherwise,
1342      * accidents can happen. If not with Postfix, then with other software.
1343      */
1344     if (unsafe() != 0)
1345 	msg_fatal("this postfix command must not run as a set-uid process");
1346     if (getuid())
1347 	msg_fatal("use of this command is reserved for the superuser");
1348 
1349     /*
1350      * Parse JCL.
1351      *
1352      * First, find out what kind of actions are requested, without executing
1353      * them. Later, we execute actions in mostly user-specified order.
1354      */
1355 #define GETOPT_LIST "c:d:e:f:h:H:pr:sSv"
1356 
1357     saved_optind = optind;
1358     while ((c = GETOPT(argc, argv, GETOPT_LIST)) > 0) {
1359 	switch (c) {
1360 	default:
1361 	    msg_fatal("usage: %s "
1362 		      "[-c config_dir] "
1363 		      "[-d queue_id (delete)] "
1364 		      "[-e queue_id (expire)] "
1365 		      "[-f queue_id (expire and/or un-hold)] "
1366 		      "[-h queue_id (hold)] [-H queue_id (un-hold)] "
1367 		      "[-p (purge temporary files)] [-r queue_id (requeue)] "
1368 		      "[-s (structure fix)] [-S (redundant structure fix)]"
1369 		      "[-v (verbose)] [queue...]", argv[0]);
1370 	case 'c':
1371 	    if (*optarg != '/')
1372 		msg_fatal("-c requires absolute pathname");
1373 	    if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
1374 		msg_fatal("setenv: %m");
1375 	    break;
1376 	case 'd':
1377 	    action |= (strcmp(optarg, "ALL") == 0 ?
1378 		       ACTION_DELETE_ALL : ACTION_DELETE_ONE);
1379 	    break;
1380 	case 'e':
1381 	    action |= (strcmp(optarg, "ALL") == 0 ?
1382 		       ACTION_EXPIRE_ALL : ACTION_EXPIRE_ONE);
1383 	    break;
1384 	case 'f':
1385 	    action |= (strcmp(optarg, "ALL") == 0 ?
1386 		       ACTION_EXP_REL_ALL : ACTION_EXP_REL_ONE);
1387 	    break;
1388 	case 'h':
1389 	    action |= (strcmp(optarg, "ALL") == 0 ?
1390 		       ACTION_HOLD_ALL : ACTION_HOLD_ONE);
1391 	    break;
1392 	case 'H':
1393 	    action |= (strcmp(optarg, "ALL") == 0 ?
1394 		       ACTION_RELEASE_ALL : ACTION_RELEASE_ONE);
1395 	    break;
1396 	case 'p':
1397 	    action |= ACTION_PURGE;
1398 	    break;
1399 	case 'r':
1400 	    action |= (strcmp(optarg, "ALL") == 0 ?
1401 		       ACTION_REQUEUE_ALL : ACTION_REQUEUE_ONE);
1402 	    break;
1403 	case 'S':
1404 	    action |= ACTION_STRUCT_RED;
1405 	    /* FALLTHROUGH */
1406 	case 's':
1407 	    action |= ACTION_STRUCT;
1408 	    break;
1409 	case 'v':
1410 	    msg_verbose++;
1411 	    break;
1412 	}
1413     }
1414 
1415     /*
1416      * Read the global configuration file and extract configuration
1417      * information. The -c command option can override the default
1418      * configuration directory location.
1419      */
1420     mail_conf_read();
1421     /* Enforce consistent operation of different Postfix parts. */
1422     import_env = mail_parm_split(VAR_IMPORT_ENVIRON, var_import_environ);
1423     update_env(import_env->argv);
1424     argv_free(import_env);
1425     /* Re-evaluate mail_task() after reading main.cf. */
1426     maillog_client_init(mail_task(argv[0]),
1427 			MAILLOG_CLIENT_FLAG_LOGWRITER_FALLBACK);
1428     if (chdir(var_queue_dir))
1429 	msg_fatal("chdir %s: %m", var_queue_dir);
1430 
1431     /*
1432      * All file/directory updates must be done as the mail system owner. This
1433      * is because Postfix daemons manipulate the queue with those same
1434      * privileges, so directories must be created with the right ownership.
1435      *
1436      * Running as a non-root user is also required for security reasons. When
1437      * the Postfix queue hierarchy is compromised, an attacker could trick us
1438      * into entering other file hierarchies and afflicting damage. Running as
1439      * a non-root user limits the damage to the already compromised mail
1440      * owner.
1441      */
1442     set_ugid(var_owner_uid, var_owner_gid);
1443 
1444     /*
1445      * Be sure to log a warning if we do not finish structural repair. Maybe
1446      * we should have an fsck-style "clean" flag so Postfix will not start
1447      * with a broken queue.
1448      *
1449      * Set up signal handlers after permanently dropping super-user privileges,
1450      * so that signal handlers will always run with the correct privileges.
1451      *
1452      * XXX Don't enable SIGHUP or SIGTERM if it was ignored by the parent.
1453      *
1454      * interrupted() uses the in-kernel SIGINT handler address as an atomic
1455      * variable to prevent nested interrupted() calls. For this reason, the
1456      * SIGINT handler must be configured before other signal handlers are
1457      * allowed to invoke interrupted(). See also similar code in postdrop.
1458      */
1459     signal(SIGINT, interrupted);
1460     signal(SIGQUIT, interrupted);
1461     if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
1462 	signal(SIGTERM, interrupted);
1463     if (signal(SIGHUP, SIG_IGN) == SIG_DFL)
1464 	signal(SIGHUP, interrupted);
1465     msg_cleanup(fatal_warning);
1466 
1467     /*
1468      * Execute the explicitly specified (or default) action, on the
1469      * explicitly specified (or default) queues.
1470      *
1471      * XXX Work around gcc const brain damage.
1472      *
1473      * XXX The file name/inode number fix should always run over all message
1474      * file directories, and should always be preceded by a subdirectory
1475      * level check of the bounce and defer logfile directories.
1476      */
1477     if (action == 0)
1478 	action = ACTION_DEFAULT;
1479     if (argv[optind] != 0)
1480 	queues = (const char **) argv + optind;
1481     else
1482 	queues = (const char **) default_queues;
1483 
1484     /*
1485      * Basic queue maintenance, including mass name-to-inode fixing. This
1486      * ensures that queue files are in the right place before any other
1487      * operations are done.
1488      */
1489     if (action & ACTIONS_FOR_REPAIR)
1490 	super(queues, action & ACTIONS_FOR_REPAIR);
1491 
1492     /*
1493      * If any file names needed changing to match the message file inode
1494      * number, those files were named newqeueid#FIX. We need a second pass to
1495      * strip the suffix from the new queue ID, and to complete any requested
1496      * operations that had to be skipped in the first pass.
1497      */
1498     if (inode_mismatch > 0)
1499 	super(queues, action & ACTIONS_FOR_REPAIR);
1500 
1501     /*
1502      * Don't do actions by queue file name if any queue files changed name
1503      * because they did not match the queue file inode number. We could be
1504      * acting on the wrong queue file and lose mail.
1505      */
1506     if ((action & ACTIONS_BY_QUEUE_ID)
1507 	&& (inode_mismatch > 0 || inode_fixed > 0)) {
1508 	msg_error("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS");
1509 	msg_fatal("CHECK YOUR QUEUE IDS AND RE-ISSUE THE COMMAND");
1510     }
1511 
1512     /*
1513      * Execute actions by queue ID and by wildcard in the user-specified
1514      * order.
1515      */
1516     optind = saved_optind;
1517     while ((c = GETOPT(argc, argv, GETOPT_LIST)) > 0) {
1518 	switch (c) {
1519 	default:
1520 	    msg_panic("%s: unexpected option: %c", argv[0], c);
1521 	case 'c':
1522 	case 'p':
1523 	case 'S':
1524 	case 's':
1525 	case 'v':
1526 	    /* Already handled. */
1527 	    break;
1528 	case 'd':
1529 	    if (strcmp(optarg, "ALL") == 0)
1530 		super(queues, ACTION_DELETE_ALL);
1531 	    else if (strcmp(optarg, "-") == 0)
1532 		operate_stream(VSTREAM_IN, delete_one, queues);
1533 	    else
1534 		delete_one(queues, optarg);
1535 	    break;
1536 	case 'e':
1537 	    if (strcmp(optarg, "ALL") == 0)
1538 		super(queues, ACTION_EXPIRE_ALL);
1539 	    else if (strcmp(optarg, "-") == 0)
1540 		operate_stream(VSTREAM_IN, expire_one, queues);
1541 	    else
1542 		expire_one(queues, optarg);
1543 	    break;
1544 	case 'f':
1545 	    if (strcmp(optarg, "ALL") == 0)
1546 		super(queues, ACTION_EXP_REL_ALL);
1547 	    else if (strcmp(optarg, "-") == 0)
1548 		operate_stream(VSTREAM_IN, exp_rel_one, queues);
1549 	    else
1550 		exp_rel_one(queues, optarg);
1551 	    break;
1552 	case 'h':
1553 	    if (strcmp(optarg, "ALL") == 0)
1554 		super(queues, ACTION_HOLD_ALL);
1555 	    else if (strcmp(optarg, "-") == 0)
1556 		operate_stream(VSTREAM_IN, hold_one, queues);
1557 	    else
1558 		hold_one(queues, optarg);
1559 	    break;
1560 	case 'H':
1561 	    if (strcmp(optarg, "ALL") == 0)
1562 		super(queues, ACTION_RELEASE_ALL);
1563 	    else if (strcmp(optarg, "-") == 0)
1564 		operate_stream(VSTREAM_IN, release_one, queues);
1565 	    else
1566 		release_one(queues, optarg);
1567 	    break;
1568 	case 'r':
1569 	    if (strcmp(optarg, "ALL") == 0)
1570 		super(queues, ACTION_REQUEUE_ALL);
1571 	    else if (strcmp(optarg, "-") == 0)
1572 		operate_stream(VSTREAM_IN, requeue_one, queues);
1573 	    else
1574 		requeue_one(queues, optarg);
1575 	    break;
1576 	}
1577     }
1578 
1579     /*
1580      * Report.
1581      */
1582     if (action & (ACTION_REQUEUE_ONE | ACTION_REQUEUE_ALL))
1583 	msg_info("Requeued: %d message%s", message_requeued,
1584 		 message_requeued != 1 ? "s" : "");
1585     if (action & (ACTION_DELETE_ONE | ACTION_DELETE_ALL))
1586 	msg_info("Deleted: %d message%s", message_deleted,
1587 		 message_deleted != 1 ? "s" : "");
1588     if (action & (ACTION_EXPIRE_ONE | ACTION_EXPIRE_ALL
1589 		  | ACTION_EXP_REL_ONE | ACTION_EXP_REL_ALL))
1590 	msg_info("Force-expired: %d message%s", message_expired,
1591 		 message_expired != 1 ? "s" : "");
1592     if (action & (ACTION_HOLD_ONE | ACTION_HOLD_ALL))
1593 	msg_info("Placed on hold: %d message%s",
1594 		 message_held, message_held != 1 ? "s" : "");
1595     if (action & (ACTION_RELEASE_ONE | ACTION_RELEASE_ALL
1596 		  | ACTION_EXP_REL_ONE | ACTION_EXP_REL_ALL))
1597 	msg_info("Released from hold: %d message%s",
1598 		 message_released, message_released != 1 ? "s" : "");
1599     if (inode_fixed > 0)
1600 	msg_info("Renamed to match inode number: %d message%s", inode_fixed,
1601 		 inode_fixed != 1 ? "s" : "");
1602     if (inode_mismatch > 0 || inode_fixed > 0)
1603 	msg_warn("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS");
1604 
1605     exit(0);
1606 }
1607