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