xref: /netbsd-src/external/ibm-public/postfix/dist/src/sendmail/sendmail.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1*67b9b338Schristos /*	$NetBSD: sendmail.c,v 1.4 2022/10/08 16:12:49 christos Exp $	*/
241fbaed0Stron 
341fbaed0Stron /*++
441fbaed0Stron /* NAME
541fbaed0Stron /*	sendmail 1
641fbaed0Stron /* SUMMARY
741fbaed0Stron /*	Postfix to Sendmail compatibility interface
841fbaed0Stron /* SYNOPSIS
941fbaed0Stron /*	\fBsendmail\fR [\fIoption ...\fR] [\fIrecipient ...\fR]
1041fbaed0Stron /*
1141fbaed0Stron /*	\fBmailq\fR
1241fbaed0Stron /*	\fBsendmail -bp\fR
1341fbaed0Stron /*
1441fbaed0Stron /*	\fBnewaliases\fR
1541fbaed0Stron /*	\fBsendmail -I\fR
1641fbaed0Stron /* DESCRIPTION
1741fbaed0Stron /*	The Postfix \fBsendmail\fR(1) command implements the Postfix
1841fbaed0Stron /*	to Sendmail compatibility interface.
1941fbaed0Stron /*	For the sake of compatibility with existing applications, some
2041fbaed0Stron /*	Sendmail command-line options are recognized but silently ignored.
2141fbaed0Stron /*
2241fbaed0Stron /*	By default, Postfix \fBsendmail\fR(1) reads a message from
2341fbaed0Stron /*	standard input
2441fbaed0Stron /*	until EOF or until it reads a line with only a \fB.\fR character,
2541fbaed0Stron /*	and arranges for delivery.  Postfix \fBsendmail\fR(1) relies on the
2641fbaed0Stron /*	\fBpostdrop\fR(1) command to create a queue file in the \fBmaildrop\fR
2741fbaed0Stron /*	directory.
2841fbaed0Stron /*
2941fbaed0Stron /*	Specific command aliases are provided for other common modes of
3041fbaed0Stron /*	operation:
3141fbaed0Stron /* .IP \fBmailq\fR
3241fbaed0Stron /*	List the mail queue. Each entry shows the queue file ID, message
3341fbaed0Stron /*	size, arrival time, sender, and the recipients that still need to
3441fbaed0Stron /*	be delivered.  If mail could not be delivered upon the last attempt,
3541fbaed0Stron /*	the reason for failure is shown. The queue ID string is
3641fbaed0Stron /*	followed by an optional status character:
3741fbaed0Stron /* .RS
3841fbaed0Stron /* .IP \fB*\fR
3941fbaed0Stron /*	The message is in the \fBactive\fR queue, i.e. the message is
4041fbaed0Stron /*	selected for delivery.
4141fbaed0Stron /* .IP \fB!\fR
4241fbaed0Stron /*	The message is in the \fBhold\fR queue, i.e. no further delivery
4341fbaed0Stron /*	attempt will be made until the mail is taken off hold.
44*67b9b338Schristos /* .IP \fB#\fR
45*67b9b338Schristos /*	The message is forced to expire. See the \fBpostsuper\fR(1)
46*67b9b338Schristos /*	options \fB-e\fR or \fB-f\fR.
4741fbaed0Stron /* .RE
4841fbaed0Stron /* .IP
4941fbaed0Stron /*	This mode of operation is implemented by executing the
5041fbaed0Stron /*	\fBpostqueue\fR(1) command.
5141fbaed0Stron /* .IP \fBnewaliases\fR
5241fbaed0Stron /*	Initialize the alias database.  If no input file is specified (with
5341fbaed0Stron /*	the \fB-oA\fR option, see below), the program processes the file(s)
5441fbaed0Stron /*	specified with the \fBalias_database\fR configuration parameter.
5541fbaed0Stron /*	If no alias database type is specified, the program uses the type
5641fbaed0Stron /*	specified with the \fBdefault_database_type\fR configuration parameter.
5741fbaed0Stron /*	This mode of operation is implemented by running the \fBpostalias\fR(1)
5841fbaed0Stron /*	command.
5941fbaed0Stron /* .sp
6041fbaed0Stron /*	Note: it may take a minute or so before an alias database update
6141fbaed0Stron /*	becomes visible. Use the "\fBpostfix reload\fR" command to eliminate
6241fbaed0Stron /*	this delay.
6341fbaed0Stron /* .PP
6441fbaed0Stron /*	These and other features can be selected by specifying the
6541fbaed0Stron /*	appropriate combination of command-line options. Some features are
6641fbaed0Stron /*	controlled by parameters in the \fBmain.cf\fR configuration file.
6741fbaed0Stron /*
6841fbaed0Stron /*	The following options are recognized:
6941fbaed0Stron /* .IP "\fB-Am\fR (ignored)"
7041fbaed0Stron /* .IP "\fB-Ac\fR (ignored)"
7141fbaed0Stron /*	Postfix sendmail uses the same configuration file regardless of
7241fbaed0Stron /*	whether or not a message is an initial submission.
7341fbaed0Stron /* .IP "\fB-B \fIbody_type\fR"
7441fbaed0Stron /*	The message body MIME type: \fB7BIT\fR or \fB8BITMIME\fR.
7541fbaed0Stron /* .IP \fB-bd\fR
7641fbaed0Stron /*	Go into daemon mode. This mode of operation is implemented by
7741fbaed0Stron /*	executing the "\fBpostfix start\fR" command.
7841fbaed0Stron /* .IP "\fB-bh\fR (ignored)"
7941fbaed0Stron /* .IP "\fB-bH\fR (ignored)"
8041fbaed0Stron /*	Postfix has no persistent host status database.
8141fbaed0Stron /* .IP \fB-bi\fR
8241fbaed0Stron /*	Initialize alias database. See the \fBnewaliases\fR
8341fbaed0Stron /*	command above.
84e6ca80d4Stron /* .IP \fB-bl\fR
85e6ca80d4Stron /*	Go into daemon mode. To accept only local connections as
86*67b9b338Schristos /*	with Sendmail's \fB-bl\fR option, specify "\fBinet_interfaces
87e6ca80d4Stron /*	= loopback\fR" in the Postfix \fBmain.cf\fR configuration
88e6ca80d4Stron /*	file.
8941fbaed0Stron /* .IP \fB-bm\fR
9041fbaed0Stron /*	Read mail from standard input and arrange for delivery.
9141fbaed0Stron /*	This is the default mode of operation.
9241fbaed0Stron /* .IP \fB-bp\fR
9341fbaed0Stron /*	List the mail queue. See the \fBmailq\fR command above.
9441fbaed0Stron /* .IP \fB-bs\fR
9541fbaed0Stron /*	Stand-alone SMTP server mode. Read SMTP commands from
9641fbaed0Stron /*	standard input, and write responses to standard output.
9741fbaed0Stron /*	In stand-alone SMTP server mode, mail relaying and other
9841fbaed0Stron /*	access controls are disabled by default. To enable them,
9941fbaed0Stron /*	run the process as the \fBmail_owner\fR user.
10041fbaed0Stron /* .sp
10141fbaed0Stron /*	This mode of operation is implemented by running the
10241fbaed0Stron /*	\fBsmtpd\fR(8) daemon.
10341fbaed0Stron /* .IP \fB-bv\fR
10441fbaed0Stron /*	Do not collect or deliver a message. Instead, send an email
10541fbaed0Stron /*	report after verifying each recipient address.  This is useful
10641fbaed0Stron /*	for testing address rewriting and routing configurations.
10741fbaed0Stron /* .sp
10841fbaed0Stron /*	This feature is available in Postfix version 2.1 and later.
10941fbaed0Stron /* .IP "\fB-C \fIconfig_file\fR"
11041fbaed0Stron /* .IP "\fB-C \fIconfig_dir\fR"
11141fbaed0Stron /*	The path name of the Postfix \fBmain.cf\fR file, or of its
11241fbaed0Stron /*	parent directory. This information is ignored with Postfix
11341fbaed0Stron /*	versions before 2.3.
11441fbaed0Stron /*
11533881f77Schristos /*	With Postfix version 3.2 and later, a non-default directory
11633881f77Schristos /*	must be authorized in the default \fBmain.cf\fR file, through
11733881f77Schristos /*	the alternate_config_directories or multi_instance_directories
11833881f77Schristos /*	parameters.
11933881f77Schristos /*
12041fbaed0Stron /*	With all Postfix versions, you can specify a directory pathname
12141fbaed0Stron /*	with the MAIL_CONFIG environment variable to override the
12241fbaed0Stron /*	location of configuration files.
123e262b48eSchristos /* .IP "\fB-F \fIfull_name\fR"
12441fbaed0Stron /*	Set the sender full name. This overrides the NAME environment
12541fbaed0Stron /*	variable, and is used only with messages that
12641fbaed0Stron /*	have no \fBFrom:\fR message header.
12741fbaed0Stron /* .IP "\fB-f \fIsender\fR"
12841fbaed0Stron /*	Set the envelope sender address. This is the address where
12941fbaed0Stron /*	delivery problems are sent to. With Postfix versions before 2.1, the
13041fbaed0Stron /*	\fBErrors-To:\fR message header overrides the error return address.
13141fbaed0Stron /* .IP \fB-G\fR
13241fbaed0Stron /*	Gateway (relay) submission, as opposed to initial user
13341fbaed0Stron /*	submission.  Either do not rewrite addresses at all, or
13441fbaed0Stron /*	update incomplete addresses with the domain information
13541fbaed0Stron /*	specified with \fBremote_header_rewrite_domain\fR.
13641fbaed0Stron /*
13741fbaed0Stron /*	This option is ignored before Postfix version 2.3.
13841fbaed0Stron /* .IP "\fB-h \fIhop_count\fR (ignored)"
13941fbaed0Stron /*	Hop count limit. Use the \fBhopcount_limit\fR configuration
14041fbaed0Stron /*	parameter instead.
14141fbaed0Stron /* .IP \fB-I\fR
14241fbaed0Stron /*	Initialize alias database. See the \fBnewaliases\fR
14341fbaed0Stron /*	command above.
14441fbaed0Stron /* .IP "\fB-i\fR"
145*67b9b338Schristos /*	When reading a message from standard input, don't treat a line
14641fbaed0Stron /*	with only a \fB.\fR character as the end of input.
14741fbaed0Stron /* .IP "\fB-L \fIlabel\fR (ignored)"
14841fbaed0Stron /*	The logging label. Use the \fBsyslog_name\fR configuration
14941fbaed0Stron /*	parameter instead.
15041fbaed0Stron /* .IP "\fB-m\fR (ignored)"
15141fbaed0Stron /*	Backwards compatibility.
15241fbaed0Stron /* .IP "\fB-N \fIdsn\fR (default: 'delay, failure')"
15341fbaed0Stron /*	Delivery status notification control. Specify either a
15441fbaed0Stron /*	comma-separated list with one or more of \fBfailure\fR (send
15541fbaed0Stron /*	notification when delivery fails), \fBdelay\fR (send
15641fbaed0Stron /*	notification when delivery is delayed), or \fBsuccess\fR
15741fbaed0Stron /*	(send notification when the message is delivered); or specify
15841fbaed0Stron /*	\fBnever\fR (don't send any notifications at all).
15941fbaed0Stron /*
16041fbaed0Stron /*	This feature is available in Postfix 2.3 and later.
16141fbaed0Stron /* .IP "\fB-n\fR (ignored)"
16241fbaed0Stron /*	Backwards compatibility.
16341fbaed0Stron /* .IP "\fB-oA\fIalias_database\fR"
16441fbaed0Stron /*	Non-default alias database. Specify \fIpathname\fR or
16541fbaed0Stron /*	\fItype\fR:\fIpathname\fR. See \fBpostalias\fR(1) for
16641fbaed0Stron /*	details.
16741fbaed0Stron /* .IP "\fB-O \fIoption=value\fR (ignored)"
168e6ca80d4Stron /*	Set the named \fIoption\fR to \fIvalue\fR. Use the equivalent
169e6ca80d4Stron /*	configuration parameter in \fBmain.cf\fR instead.
17041fbaed0Stron /* .IP "\fB-o7\fR (ignored)"
17141fbaed0Stron /* .IP "\fB-o8\fR (ignored)"
17241fbaed0Stron /*	To send 8-bit or binary content, use an appropriate MIME encapsulation
17341fbaed0Stron /*	and specify the appropriate \fB-B\fR command-line option.
17441fbaed0Stron /* .IP "\fB-oi\fR"
175*67b9b338Schristos /*	When reading a message from standard input, don't treat a line
17641fbaed0Stron /*	with only a \fB.\fR character as the end of input.
17741fbaed0Stron /* .IP "\fB-om\fR (ignored)"
17841fbaed0Stron /*	The sender is never eliminated from alias etc. expansions.
17941fbaed0Stron /* .IP "\fB-o \fIx value\fR (ignored)"
18041fbaed0Stron /*	Set option \fIx\fR to \fIvalue\fR. Use the equivalent
18141fbaed0Stron /*	configuration parameter in \fBmain.cf\fR instead.
18241fbaed0Stron /* .IP "\fB-r \fIsender\fR"
18341fbaed0Stron /*	Set the envelope sender address. This is the address where
18441fbaed0Stron /*	delivery problems are sent to. With Postfix versions before 2.1, the
18541fbaed0Stron /*	\fBErrors-To:\fR message header overrides the error return address.
186e6ca80d4Stron /* .IP "\fB-R \fIreturn\fR"
187e6ca80d4Stron /*	Delivery status notification control.  Specify "hdrs" to
188e6ca80d4Stron /*	return only the header when a message bounces, "full" to
189e6ca80d4Stron /*	return a full copy (the default behavior).
190e6ca80d4Stron /*
191e6ca80d4Stron /*	The \fB-R\fR option specifies an upper bound; Postfix will
192e6ca80d4Stron /*	return only the header, when a full copy would exceed the
193e6ca80d4Stron /*	bounce_size_limit setting.
194e6ca80d4Stron /*
195e6ca80d4Stron /*	This option is ignored before Postfix version 2.10.
19641fbaed0Stron /* .IP \fB-q\fR
19741fbaed0Stron /*	Attempt to deliver all queued mail. This is implemented by
19841fbaed0Stron /*	executing the \fBpostqueue\fR(1) command.
19941fbaed0Stron /*
20041fbaed0Stron /*	Warning: flushing undeliverable mail frequently will result in
20141fbaed0Stron /*	poor delivery performance of all other mail.
20241fbaed0Stron /* .IP "\fB-q\fIinterval\fR (ignored)"
20341fbaed0Stron /*	The interval between queue runs. Use the \fBqueue_run_delay\fR
20441fbaed0Stron /*	configuration parameter instead.
20541fbaed0Stron /* .IP \fB-qI\fIqueueid\fR
20641fbaed0Stron /*	Schedule immediate delivery of mail with the specified queue
20741fbaed0Stron /*	ID.  This option is implemented by executing the
20841fbaed0Stron /*	\fBpostqueue\fR(1) command, and is available with Postfix
20941fbaed0Stron /*	version 2.4 and later.
21041fbaed0Stron /* .IP \fB-qR\fIsite\fR
21141fbaed0Stron /*	Schedule immediate delivery of all mail that is queued for the named
21241fbaed0Stron /*	\fIsite\fR. This option accepts only \fIsite\fR names that are
21341fbaed0Stron /*	eligible for the "fast flush" service, and is implemented by
21441fbaed0Stron /*	executing the \fBpostqueue\fR(1) command.
21541fbaed0Stron /*	See \fBflush\fR(8) for more information about the "fast flush"
21641fbaed0Stron /*	service.
21741fbaed0Stron /* .IP \fB-qS\fIsite\fR
21841fbaed0Stron /*	This command is not implemented. Use the slower "\fBsendmail -q\fR"
21941fbaed0Stron /*	command instead.
22041fbaed0Stron /* .IP \fB-t\fR
22141fbaed0Stron /*	Extract recipients from message headers. These are added to any
22241fbaed0Stron /*	recipients specified on the command line.
22341fbaed0Stron /*
22441fbaed0Stron /*	With Postfix versions prior to 2.1, this option requires that
22541fbaed0Stron /*	no recipient addresses are specified on the command line.
22641fbaed0Stron /* .IP "\fB-U\fR (ignored)"
22741fbaed0Stron /*	Initial user submission.
22841fbaed0Stron /* .IP "\fB-V \fIenvid\fR"
22941fbaed0Stron /*	Specify the envelope ID for notification by servers that
23041fbaed0Stron /*	support DSN.
23141fbaed0Stron /*
23241fbaed0Stron /*	This feature is available in Postfix 2.3 and later.
23341fbaed0Stron /* .IP "\fB-XV\fR (Postfix 2.2 and earlier: \fB-V\fR)"
23441fbaed0Stron /*	Variable Envelope Return Path. Given an envelope sender address
23541fbaed0Stron /*	of the form \fIowner-listname\fR@\fIorigin\fR, each recipient
23641fbaed0Stron /*	\fIuser\fR@\fIdomain\fR receives mail with a personalized envelope
23741fbaed0Stron /*	sender address.
23841fbaed0Stron /* .sp
23941fbaed0Stron /*	By default, the personalized envelope sender address is
24041fbaed0Stron /*	\fIowner-listname\fB+\fIuser\fB=\fIdomain\fR@\fIorigin\fR. The default
24141fbaed0Stron /*	\fB+\fR and \fB=\fR characters are configurable with the
24241fbaed0Stron /*	\fBdefault_verp_delimiters\fR configuration parameter.
24341fbaed0Stron /* .IP "\fB-XV\fIxy\fR (Postfix 2.2 and earlier: \fB-V\fIxy\fR)"
24441fbaed0Stron /*	As \fB-XV\fR, but uses \fIx\fR and \fIy\fR as the VERP delimiter
24541fbaed0Stron /*	characters, instead of the characters specified with the
24641fbaed0Stron /*	\fBdefault_verp_delimiters\fR configuration parameter.
24741fbaed0Stron /* .IP \fB-v\fR
24841fbaed0Stron /*	Send an email report of the first delivery attempt (Postfix
24941fbaed0Stron /*	versions 2.1 and later). Mail delivery
25041fbaed0Stron /*	always happens in the background. When multiple \fB-v\fR
25141fbaed0Stron /*	options are given, enable verbose logging for debugging purposes.
25241fbaed0Stron /* .IP "\fB-X \fIlog_file\fR (ignored)"
25341fbaed0Stron /*	Log mailer traffic. Use the \fBdebug_peer_list\fR and
25441fbaed0Stron /*	\fBdebug_peer_level\fR configuration parameters instead.
25541fbaed0Stron /* SECURITY
25641fbaed0Stron /* .ad
25741fbaed0Stron /* .fi
258*67b9b338Schristos /*	By design, this program is not set-user (or group) id.
259*67b9b338Schristos /*	It is prepared to handle message content from untrusted,
260*67b9b338Schristos /*	possibly remote, users.
261*67b9b338Schristos /*
262*67b9b338Schristos /*	However, like most Postfix programs, this program does not
263*67b9b338Schristos /*	enforce a security policy on its command-line arguments.
264*67b9b338Schristos /*	Instead, it relies on the UNIX system to enforce access
265*67b9b338Schristos /*	policies based on the effective user and group IDs of the
266*67b9b338Schristos /*	process. Concretely, this means that running Postfix commands
267*67b9b338Schristos /*	as root (from sudo or equivalent) on behalf of a non-root
268*67b9b338Schristos /*	user is likely to create privilege escalation opportunities.
269*67b9b338Schristos /*
270*67b9b338Schristos /*	If an application runs any Postfix programs on behalf of
271*67b9b338Schristos /*	users that do not have normal shell access to Postfix
272*67b9b338Schristos /*	commands, then that application MUST restrict user-specified
273*67b9b338Schristos /*	command-line arguments to avoid privilege escalation.
274*67b9b338Schristos /* .IP \(bu
275*67b9b338Schristos /*	Filter all command-line arguments, for example arguments
276*67b9b338Schristos /*	that contain a pathname or that specify a database access
277*67b9b338Schristos /*	method. These pathname checks must reject user-controlled
278*67b9b338Schristos /*	symlinks or hardlinks to sensitive files, and must not be
279*67b9b338Schristos /*	vulnerable to TOCTOU race attacks.
280*67b9b338Schristos /* .IP \(bu
281*67b9b338Schristos /*	Disable command options processing for all command arguments
282*67b9b338Schristos /*	that contain user-specified data. For example, the Postfix
283*67b9b338Schristos /*	\fBsendmail\fR(1) command line MUST be structured as follows:
284*67b9b338Schristos /*
285*67b9b338Schristos /* .nf
286*67b9b338Schristos /*	    \fB/path/to/sendmail\fR \fIsystem-arguments\fR \fB--\fR \fIuser-arguments\fR
287*67b9b338Schristos /* .fi
288*67b9b338Schristos /*
289*67b9b338Schristos /*	Here, the "\fB--\fR" disables command option processing for
290*67b9b338Schristos /*	all \fIuser-arguments\fR that follow.
291*67b9b338Schristos /* .IP
292*67b9b338Schristos /*	Without the "\fB--\fR", a malicious user could enable Postfix
293*67b9b338Schristos /*	\fBsendmail\fR(1) command options, by specifying an email
294*67b9b338Schristos /*	address that starts with "\fB-\fR".
29541fbaed0Stron /* DIAGNOSTICS
29633881f77Schristos /*	Problems are logged to \fBsyslogd\fR(8) or \fBpostlogd\fR(8),
29733881f77Schristos /*	and to the standard error stream.
29841fbaed0Stron /* ENVIRONMENT
29941fbaed0Stron /* .ad
30041fbaed0Stron /* .fi
30141fbaed0Stron /* .IP \fBMAIL_CONFIG\fR
30241fbaed0Stron /*	Directory with Postfix configuration files.
30341fbaed0Stron /* .IP "\fBMAIL_VERBOSE\fR (value does not matter)"
30441fbaed0Stron /*	Enable verbose logging for debugging purposes.
30541fbaed0Stron /* .IP "\fBMAIL_DEBUG\fR (value does not matter)"
30641fbaed0Stron /*	Enable debugging with an external command, as specified with the
30741fbaed0Stron /*	\fBdebugger_command\fR configuration parameter.
30841fbaed0Stron /* .IP \fBNAME\fR
30941fbaed0Stron /*	The sender full name. This is used only with messages that
31041fbaed0Stron /*	have no \fBFrom:\fR message header. See also the \fB-F\fR
31141fbaed0Stron /*	option above.
31241fbaed0Stron /* CONFIGURATION PARAMETERS
31341fbaed0Stron /* .ad
31441fbaed0Stron /* .fi
31541fbaed0Stron /*	The following \fBmain.cf\fR parameters are especially relevant to
31641fbaed0Stron /*	this program.
31741fbaed0Stron /*	The text below provides only a parameter summary. See
31841fbaed0Stron /*	\fBpostconf\fR(5) for more details including examples.
319a30b880eStron /* COMPATIBILITY CONTROLS
320a30b880eStron /* .ad
321a30b880eStron /* .fi
322a30b880eStron /*	Available with Postfix 2.9 and later:
323a30b880eStron /* .IP "\fBsendmail_fix_line_endings (always)\fR"
324a30b880eStron /*	Controls how the Postfix sendmail command converts email message
325a30b880eStron /*	line endings from <CR><LF> into UNIX format (<LF>).
32641fbaed0Stron /* TROUBLE SHOOTING CONTROLS
32741fbaed0Stron /* .ad
32841fbaed0Stron /* .fi
32941fbaed0Stron /*	The DEBUG_README file gives examples of how to troubleshoot a
33041fbaed0Stron /*	Postfix system.
33141fbaed0Stron /* .IP "\fBdebugger_command (empty)\fR"
33241fbaed0Stron /*	The external command to execute when a Postfix daemon program is
33341fbaed0Stron /*	invoked with the -D option.
33441fbaed0Stron /* .IP "\fBdebug_peer_level (2)\fR"
335*67b9b338Schristos /*	The increment in verbose logging level when a nexthop destination,
336*67b9b338Schristos /*	remote client or server name or network address matches a pattern
337*67b9b338Schristos /*	given with the debug_peer_list parameter.
33841fbaed0Stron /* .IP "\fBdebug_peer_list (empty)\fR"
339*67b9b338Schristos /*	Optional list of nexthop destination, remote client or server
340*67b9b338Schristos /*	name or network address patterns that, if matched, cause the verbose
341*67b9b338Schristos /*	logging level to increase by the amount specified in $debug_peer_level.
34241fbaed0Stron /* ACCESS CONTROLS
34341fbaed0Stron /* .ad
34441fbaed0Stron /* .fi
34541fbaed0Stron /*	Available in Postfix version 2.2 and later:
34641fbaed0Stron /* .IP "\fBauthorized_flush_users (static:anyone)\fR"
34741fbaed0Stron /*	List of users who are authorized to flush the queue.
34841fbaed0Stron /* .IP "\fBauthorized_mailq_users (static:anyone)\fR"
34941fbaed0Stron /*	List of users who are authorized to view the queue.
35041fbaed0Stron /* .IP "\fBauthorized_submit_users (static:anyone)\fR"
35141fbaed0Stron /*	List of users who are authorized to submit mail with the \fBsendmail\fR(1)
35241fbaed0Stron /*	command (and with the privileged \fBpostdrop\fR(1) helper command).
35341fbaed0Stron /* RESOURCE AND RATE CONTROLS
35441fbaed0Stron /* .ad
35541fbaed0Stron /* .fi
35641fbaed0Stron /* .IP "\fBbounce_size_limit (50000)\fR"
35741fbaed0Stron /*	The maximal amount of original message text that is sent in a
35841fbaed0Stron /*	non-delivery notification.
35941fbaed0Stron /* .IP "\fBfork_attempts (5)\fR"
36041fbaed0Stron /*	The maximal number of attempts to fork() a child process.
36141fbaed0Stron /* .IP "\fBfork_delay (1s)\fR"
36241fbaed0Stron /*	The delay between attempts to fork() a child process.
36341fbaed0Stron /* .IP "\fBhopcount_limit (50)\fR"
36441fbaed0Stron /*	The maximal number of Received:  message headers that is allowed
36541fbaed0Stron /*	in the primary message headers.
36641fbaed0Stron /* .IP "\fBqueue_run_delay (300s)\fR"
36741fbaed0Stron /*	The time between deferred queue scans by the queue manager;
36841fbaed0Stron /*	prior to Postfix 2.4 the default value was 1000s.
36941fbaed0Stron /* FAST FLUSH CONTROLS
37041fbaed0Stron /* .ad
37141fbaed0Stron /* .fi
37241fbaed0Stron /*	The ETRN_README file describes configuration and operation
37341fbaed0Stron /*	details for the Postfix "fast flush" service.
37441fbaed0Stron /* .IP "\fBfast_flush_domains ($relay_domains)\fR"
37541fbaed0Stron /*	Optional list of destinations that are eligible for per-destination
37641fbaed0Stron /*	logfiles with mail that is queued to those destinations.
37741fbaed0Stron /* VERP CONTROLS
37841fbaed0Stron /* .ad
37941fbaed0Stron /* .fi
38041fbaed0Stron /*	The VERP_README file describes configuration and operation
38141fbaed0Stron /*	details of Postfix support for variable envelope return
38241fbaed0Stron /*	path addresses.
38341fbaed0Stron /* .IP "\fBdefault_verp_delimiters (+=)\fR"
38441fbaed0Stron /*	The two default VERP delimiter characters.
38541fbaed0Stron /* .IP "\fBverp_delimiter_filter (-=+)\fR"
38641fbaed0Stron /*	The characters Postfix accepts as VERP delimiter characters on the
38741fbaed0Stron /*	Postfix \fBsendmail\fR(1) command line and in SMTP commands.
38841fbaed0Stron /* MISCELLANEOUS CONTROLS
38941fbaed0Stron /* .ad
39041fbaed0Stron /* .fi
39141fbaed0Stron /* .IP "\fBalias_database (see 'postconf -d' output)\fR"
39241fbaed0Stron /*	The alias databases for \fBlocal\fR(8) delivery that are updated with
39341fbaed0Stron /*	"\fBnewaliases\fR" or with "\fBsendmail -bi\fR".
39441fbaed0Stron /* .IP "\fBcommand_directory (see 'postconf -d' output)\fR"
39541fbaed0Stron /*	The location of all postfix administrative commands.
39641fbaed0Stron /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
39741fbaed0Stron /*	The default location of the Postfix main.cf and master.cf
39841fbaed0Stron /*	configuration files.
39941fbaed0Stron /* .IP "\fBdaemon_directory (see 'postconf -d' output)\fR"
40041fbaed0Stron /*	The directory with Postfix support programs and daemon programs.
40141fbaed0Stron /* .IP "\fBdefault_database_type (see 'postconf -d' output)\fR"
40241fbaed0Stron /*	The default database type for use in \fBnewaliases\fR(1), \fBpostalias\fR(1)
40341fbaed0Stron /*	and \fBpostmap\fR(1) commands.
40441fbaed0Stron /* .IP "\fBdelay_warning_time (0h)\fR"
405e6ca80d4Stron /*	The time after which the sender receives a copy of the message
406e6ca80d4Stron /*	headers of mail that is still queued.
40733881f77Schristos /* .IP "\fBimport_environment (see 'postconf -d' output)\fR"
408*67b9b338Schristos /*	The list of environment variables that a privileged Postfix
40933881f77Schristos /*	process will import from a non-Postfix parent process, or name=value
41033881f77Schristos /*	environment overrides.
41141fbaed0Stron /* .IP "\fBmail_owner (postfix)\fR"
41241fbaed0Stron /*	The UNIX system account that owns the Postfix queue and most Postfix
41341fbaed0Stron /*	daemon processes.
41441fbaed0Stron /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
41541fbaed0Stron /*	The location of the Postfix top-level queue directory.
41641fbaed0Stron /* .IP "\fBremote_header_rewrite_domain (empty)\fR"
41741fbaed0Stron /*	Don't rewrite message headers from remote clients at all when
41841fbaed0Stron /*	this parameter is empty; otherwise, rewrite message headers and
41941fbaed0Stron /*	append the specified domain name to incomplete addresses.
42041fbaed0Stron /* .IP "\fBsyslog_facility (mail)\fR"
42141fbaed0Stron /*	The syslog facility of Postfix logging.
42241fbaed0Stron /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
42333881f77Schristos /*	A prefix that is prepended to the process name in syslog
42433881f77Schristos /*	records, so that, for example, "smtpd" becomes "prefix/smtpd".
42533881f77Schristos /* .PP
42633881f77Schristos /*	Postfix 3.2 and later:
42733881f77Schristos /* .IP "\fBalternate_config_directories (empty)\fR"
42833881f77Schristos /*	A list of non-default Postfix configuration directories that may
42933881f77Schristos /*	be specified with "-c config_directory" on the command line (in the
43033881f77Schristos /*	case of \fBsendmail\fR(1), with the "-C" option), or via the MAIL_CONFIG
43133881f77Schristos /*	environment parameter.
43233881f77Schristos /* .IP "\fBmulti_instance_directories (empty)\fR"
43333881f77Schristos /*	An optional list of non-default Postfix configuration directories;
43433881f77Schristos /*	these directories belong to additional Postfix instances that share
43533881f77Schristos /*	the Postfix executable files and documentation with the default
43633881f77Schristos /*	Postfix instance, and that are started, stopped, etc., together
43733881f77Schristos /*	with the default Postfix instance.
43841fbaed0Stron /* FILES
43941fbaed0Stron /*	/var/spool/postfix, mail queue
44041fbaed0Stron /*	/etc/postfix, configuration files
44141fbaed0Stron /* SEE ALSO
44241fbaed0Stron /*	pickup(8), mail pickup daemon
44341fbaed0Stron /*	qmgr(8), queue manager
44441fbaed0Stron /*	smtpd(8), SMTP server
44541fbaed0Stron /*	flush(8), fast flush service
44641fbaed0Stron /*	postsuper(1), queue maintenance
44741fbaed0Stron /*	postalias(1), create/update/query alias database
44841fbaed0Stron /*	postdrop(1), mail posting utility
44941fbaed0Stron /*	postfix(1), mail system control
45041fbaed0Stron /*	postqueue(1), mail queue control
45133881f77Schristos /*	postlogd(8), Postfix logging
45241fbaed0Stron /*	syslogd(8), system logging
45341fbaed0Stron /* README_FILES
45441fbaed0Stron /* .ad
45541fbaed0Stron /* .fi
45641fbaed0Stron /*	Use "\fBpostconf readme_directory\fR" or
45741fbaed0Stron /*	"\fBpostconf html_directory\fR" to locate this information.
45841fbaed0Stron /* .na
45941fbaed0Stron /* .nf
46041fbaed0Stron /*	DEBUG_README, Postfix debugging howto
46141fbaed0Stron /*	ETRN_README, Postfix ETRN howto
46241fbaed0Stron /*	VERP_README, Postfix VERP howto
46341fbaed0Stron /* LICENSE
46441fbaed0Stron /* .ad
46541fbaed0Stron /* .fi
46641fbaed0Stron /*	The Secure Mailer license must be distributed with this software.
46741fbaed0Stron /* AUTHOR(S)
46841fbaed0Stron /*	Wietse Venema
46941fbaed0Stron /*	IBM T.J. Watson Research
47041fbaed0Stron /*	P.O. Box 704
47141fbaed0Stron /*	Yorktown Heights, NY 10598, USA
472e262b48eSchristos /*
473e262b48eSchristos /*	Wietse Venema
474e262b48eSchristos /*	Google, Inc.
475e262b48eSchristos /*	111 8th Avenue
476e262b48eSchristos /*	New York, NY 10011, USA
47741fbaed0Stron /*--*/
47841fbaed0Stron 
47941fbaed0Stron /* System library. */
48041fbaed0Stron 
48141fbaed0Stron #include <sys_defs.h>
48241fbaed0Stron #include <sys/stat.h>
48341fbaed0Stron #include <unistd.h>
48441fbaed0Stron #include <string.h>
48541fbaed0Stron #include <stdio.h>			/* remove() */
48641fbaed0Stron #include <stdlib.h>
48741fbaed0Stron #include <signal.h>
48841fbaed0Stron #include <fcntl.h>
48941fbaed0Stron #include <time.h>
49041fbaed0Stron #include <errno.h>
49141fbaed0Stron #include <ctype.h>
49241fbaed0Stron #include <stdarg.h>
49341fbaed0Stron #include <sysexits.h>
49441fbaed0Stron 
49541fbaed0Stron /* Utility library. */
49641fbaed0Stron 
49741fbaed0Stron #include <msg.h>
49841fbaed0Stron #include <mymalloc.h>
49941fbaed0Stron #include <vstream.h>
50041fbaed0Stron #include <msg_vstream.h>
50141fbaed0Stron #include <vstring_vstream.h>
50241fbaed0Stron #include <username.h>
50341fbaed0Stron #include <fullname.h>
50441fbaed0Stron #include <argv.h>
50541fbaed0Stron #include <safe.h>
50641fbaed0Stron #include <iostuff.h>
50741fbaed0Stron #include <stringops.h>
50841fbaed0Stron #include <set_ugid.h>
50941fbaed0Stron #include <connect.h>
51041fbaed0Stron #include <split_at.h>
511a30b880eStron #include <name_code.h>
512a30b880eStron #include <warn_stat.h>
51333881f77Schristos #include <clean_env.h>
51433881f77Schristos #include <maillog_client.h>
51541fbaed0Stron 
51641fbaed0Stron /* Global library. */
51741fbaed0Stron 
51841fbaed0Stron #include <mail_queue.h>
51941fbaed0Stron #include <mail_proto.h>
52041fbaed0Stron #include <mail_params.h>
52141fbaed0Stron #include <mail_version.h>
52241fbaed0Stron #include <record.h>
52341fbaed0Stron #include <rec_type.h>
52441fbaed0Stron #include <rec_streamlf.h>
52541fbaed0Stron #include <mail_conf.h>
52641fbaed0Stron #include <cleanup_user.h>
52741fbaed0Stron #include <mail_task.h>
52841fbaed0Stron #include <mail_run.h>
52941fbaed0Stron #include <debug_process.h>
53041fbaed0Stron #include <tok822.h>
53141fbaed0Stron #include <mail_flush.h>
53241fbaed0Stron #include <mail_stream.h>
53341fbaed0Stron #include <verp_sender.h>
53441fbaed0Stron #include <deliver_request.h>
53541fbaed0Stron #include <mime_state.h>
53641fbaed0Stron #include <header_opts.h>
53733881f77Schristos #include <mail_dict.h>
53841fbaed0Stron #include <user_acl.h>
53941fbaed0Stron #include <dsn_mask.h>
54033881f77Schristos #include <mail_parm_split.h>
54141fbaed0Stron 
54241fbaed0Stron /* Application-specific. */
54341fbaed0Stron 
54441fbaed0Stron  /*
54541fbaed0Stron   * Modes of operation.
54641fbaed0Stron   */
54741fbaed0Stron #define SM_MODE_ENQUEUE		1	/* delivery mode */
54841fbaed0Stron #define SM_MODE_NEWALIAS	2	/* initialize alias database */
54941fbaed0Stron #define SM_MODE_MAILQ		3	/* list mail queue */
55041fbaed0Stron #define SM_MODE_DAEMON		4	/* daemon mode */
55141fbaed0Stron #define SM_MODE_USER		5	/* user (stand-alone) mode */
55241fbaed0Stron #define SM_MODE_FLUSHQ		6	/* user (stand-alone) mode */
55341fbaed0Stron #define SM_MODE_IGNORE		7	/* ignore this mode */
55441fbaed0Stron 
55541fbaed0Stron  /*
55641fbaed0Stron   * Flag parade. Flags 8-15 are reserved for delivery request trace flags.
55741fbaed0Stron   */
55841fbaed0Stron #define SM_FLAG_AEOF	(1<<0)		/* archaic EOF */
55941fbaed0Stron #define SM_FLAG_XRCPT	(1<<1)		/* extract recipients from headers */
56041fbaed0Stron 
56141fbaed0Stron #define SM_FLAG_DEFAULT	(SM_FLAG_AEOF)
56241fbaed0Stron 
56341fbaed0Stron  /*
56441fbaed0Stron   * VERP support.
56541fbaed0Stron   */
56641fbaed0Stron static char *verp_delims;
56741fbaed0Stron 
56841fbaed0Stron  /*
56941fbaed0Stron   * Callback context for extracting recipients.
57041fbaed0Stron   */
57141fbaed0Stron typedef struct SM_STATE {
57241fbaed0Stron     VSTREAM *dst;			/* output stream */
57341fbaed0Stron     ARGV   *recipients;			/* recipients from regular headers */
57441fbaed0Stron     ARGV   *resent_recip;		/* recipients from resent headers */
57541fbaed0Stron     int     resent;			/* resent flag */
57641fbaed0Stron     const char *saved_sender;		/* for error messages */
57741fbaed0Stron     uid_t   uid;			/* for error messages */
57841fbaed0Stron     VSTRING *temp;			/* scratch buffer */
57941fbaed0Stron } SM_STATE;
58041fbaed0Stron 
58141fbaed0Stron  /*
582a30b880eStron   * Mail submission ACL, line-end fixing.
58341fbaed0Stron   */
58441fbaed0Stron char   *var_submit_acl;
585a30b880eStron char   *var_sm_fix_eol;
58641fbaed0Stron 
58741fbaed0Stron static const CONFIG_STR_TABLE str_table[] = {
58841fbaed0Stron     VAR_SUBMIT_ACL, DEF_SUBMIT_ACL, &var_submit_acl, 0, 0,
589a30b880eStron     VAR_SM_FIX_EOL, DEF_SM_FIX_EOL, &var_sm_fix_eol, 1, 0,
59041fbaed0Stron     0,
59141fbaed0Stron };
59241fbaed0Stron 
59341fbaed0Stron  /*
59441fbaed0Stron   * Silly little macros (SLMs).
59541fbaed0Stron   */
59641fbaed0Stron #define STR	vstring_str
59741fbaed0Stron 
59841fbaed0Stron /* output_text - output partial or complete text line */
59941fbaed0Stron 
output_text(void * context,int rec_type,const char * buf,ssize_t len,off_t unused_offset)60041fbaed0Stron static void output_text(void *context, int rec_type, const char *buf, ssize_t len,
60141fbaed0Stron 			        off_t unused_offset)
60241fbaed0Stron {
60341fbaed0Stron     SM_STATE *state = (SM_STATE *) context;
60441fbaed0Stron 
60541fbaed0Stron     if (rec_put(state->dst, rec_type, buf, len) < 0)
60641fbaed0Stron 	msg_fatal_status(EX_TEMPFAIL,
60741fbaed0Stron 			 "%s(%ld): error writing queue file: %m",
60841fbaed0Stron 			 state->saved_sender, (long) state->uid);
60941fbaed0Stron }
61041fbaed0Stron 
61141fbaed0Stron /* output_header - output one message header */
61241fbaed0Stron 
output_header(void * context,int header_class,const HEADER_OPTS * header_info,VSTRING * buf,off_t offset)61341fbaed0Stron static void output_header(void *context, int header_class,
61441fbaed0Stron 			          const HEADER_OPTS *header_info,
61541fbaed0Stron 			          VSTRING *buf, off_t offset)
61641fbaed0Stron {
61741fbaed0Stron     SM_STATE *state = (SM_STATE *) context;
61841fbaed0Stron     TOK822 *tree;
61941fbaed0Stron     TOK822 **addr_list;
62041fbaed0Stron     TOK822 **tpp;
62141fbaed0Stron     ARGV   *rcpt;
62241fbaed0Stron     char   *start;
62341fbaed0Stron     char   *line;
62441fbaed0Stron     char   *next_line;
62541fbaed0Stron     ssize_t len;
62641fbaed0Stron 
62741fbaed0Stron     /*
62841fbaed0Stron      * Parse the header line, and save copies of recipient addresses in the
62941fbaed0Stron      * appropriate place.
63041fbaed0Stron      */
63141fbaed0Stron     if (header_class == MIME_HDR_PRIMARY
63241fbaed0Stron 	&& header_info
63341fbaed0Stron 	&& (header_info->flags & HDR_OPT_RECIP)
63441fbaed0Stron 	&& (header_info->flags & HDR_OPT_EXTRACT)
63541fbaed0Stron 	&& (state->resent == 0 || (header_info->flags & HDR_OPT_RR))) {
63641fbaed0Stron 	if (header_info->flags & HDR_OPT_RR) {
63741fbaed0Stron 	    rcpt = state->resent_recip;
63841fbaed0Stron 	    if (state->resent == 0)
63941fbaed0Stron 		state->resent = 1;
64041fbaed0Stron 	} else
64141fbaed0Stron 	    rcpt = state->recipients;
64241fbaed0Stron 	tree = tok822_parse(STR(buf) + strlen(header_info->name) + 1);
64341fbaed0Stron 	addr_list = tok822_grep(tree, TOK822_ADDR);
64441fbaed0Stron 	for (tpp = addr_list; *tpp; tpp++) {
64541fbaed0Stron 	    tok822_internalize(state->temp, tpp[0]->head, TOK822_STR_DEFL);
64641fbaed0Stron 	    argv_add(rcpt, STR(state->temp), (char *) 0);
64741fbaed0Stron 	}
648e262b48eSchristos 	myfree((void *) addr_list);
64941fbaed0Stron 	tok822_free_tree(tree);
65041fbaed0Stron     }
65141fbaed0Stron 
65241fbaed0Stron     /*
65341fbaed0Stron      * Pipe the unmodified message header through the header line folding
65441fbaed0Stron      * routine, and ensure that long lines are chopped appropriately.
65541fbaed0Stron      */
65641fbaed0Stron     for (line = start = STR(buf); line; line = next_line) {
65741fbaed0Stron 	next_line = split_at(line, '\n');
65841fbaed0Stron 	len = next_line ? next_line - line - 1 : strlen(line);
65941fbaed0Stron 	do {
66041fbaed0Stron 	    if (len > var_line_limit) {
66141fbaed0Stron 		output_text(context, REC_TYPE_CONT, line, var_line_limit, offset);
66241fbaed0Stron 		line += var_line_limit;
66341fbaed0Stron 		len -= var_line_limit;
66441fbaed0Stron 		offset += var_line_limit;
66541fbaed0Stron 	    } else {
66641fbaed0Stron 		output_text(context, REC_TYPE_NORM, line, len, offset);
66741fbaed0Stron 		offset += len;
66841fbaed0Stron 		break;
66941fbaed0Stron 	    }
67041fbaed0Stron 	} while (len > 0);
67141fbaed0Stron 	offset += 1;
67241fbaed0Stron     }
67341fbaed0Stron }
67441fbaed0Stron 
67541fbaed0Stron /* enqueue - post one message */
67641fbaed0Stron 
enqueue(const int flags,const char * encoding,const char * dsn_envid,int dsn_ret,int dsn_notify,const char * rewrite_context,const char * sender,const char * full_name,char ** recipients)67741fbaed0Stron static void enqueue(const int flags, const char *encoding,
678e6ca80d4Stron 		         const char *dsn_envid, int dsn_ret, int dsn_notify,
67941fbaed0Stron 		            const char *rewrite_context, const char *sender,
68041fbaed0Stron 		            const char *full_name, char **recipients)
68141fbaed0Stron {
68241fbaed0Stron     VSTRING *buf;
68341fbaed0Stron     VSTREAM *dst;
68441fbaed0Stron     char   *saved_sender;
68541fbaed0Stron     char  **cpp;
68641fbaed0Stron     int     type;
68741fbaed0Stron     char   *start;
68841fbaed0Stron     int     skip_from_;
68941fbaed0Stron     TOK822 *tree;
69041fbaed0Stron     TOK822 *tp;
69141fbaed0Stron     int     rcpt_count = 0;
69241fbaed0Stron     enum {
693a30b880eStron 	STRIP_CR_DUNNO, STRIP_CR_DO, STRIP_CR_DONT, STRIP_CR_ERROR
69441fbaed0Stron     }       strip_cr;
69541fbaed0Stron     MAIL_STREAM *handle;
69641fbaed0Stron     VSTRING *postdrop_command;
69741fbaed0Stron     uid_t   uid = getuid();
69841fbaed0Stron     int     status;
699*67b9b338Schristos     VSTRING *why;			/* postdrop status message */
70041fbaed0Stron     int     naddr;
70141fbaed0Stron     int     prev_type;
70241fbaed0Stron     MIME_STATE *mime_state = 0;
70341fbaed0Stron     SM_STATE state;
70441fbaed0Stron     int     mime_errs;
70541fbaed0Stron     const char *errstr;
70641fbaed0Stron     int     addr_count;
70741fbaed0Stron     int     level;
708a30b880eStron     static NAME_CODE sm_fix_eol_table[] = {
709a30b880eStron 	SM_FIX_EOL_ALWAYS, STRIP_CR_DO,
710a30b880eStron 	SM_FIX_EOL_STRICT, STRIP_CR_DUNNO,
711a30b880eStron 	SM_FIX_EOL_NEVER, STRIP_CR_DONT,
712a30b880eStron 	0, STRIP_CR_ERROR,
713a30b880eStron     };
71441fbaed0Stron 
71541fbaed0Stron     /*
71641fbaed0Stron      * Access control is enforced in the postdrop command. The code here
71741fbaed0Stron      * merely produces a more user-friendly interface.
71841fbaed0Stron      */
719e262b48eSchristos     if ((errstr = check_user_acl_byuid(VAR_SUBMIT_ACL,
720e262b48eSchristos 				       var_submit_acl, uid)) != 0)
72141fbaed0Stron 	msg_fatal_status(EX_NOPERM,
72241fbaed0Stron 	  "User %s(%ld) is not allowed to submit mail", errstr, (long) uid);
72341fbaed0Stron 
72441fbaed0Stron     /*
72541fbaed0Stron      * Initialize.
72641fbaed0Stron      */
72741fbaed0Stron     buf = vstring_alloc(100);
72841fbaed0Stron 
72941fbaed0Stron     /*
73041fbaed0Stron      * Stop run-away process accidents by limiting the queue file size. This
73141fbaed0Stron      * is not a defense against DOS attack.
73241fbaed0Stron      */
73333881f77Schristos     if (ENFORCING_SIZE_LIMIT(var_message_limit)
73433881f77Schristos 	&& get_file_limit() > var_message_limit)
73541fbaed0Stron 	set_file_limit((off_t) var_message_limit);
73641fbaed0Stron 
73741fbaed0Stron     /*
73841fbaed0Stron      * The sender name is provided by the user. In principle, the mail pickup
73941fbaed0Stron      * service could deduce the sender name from queue file ownership, but:
74041fbaed0Stron      * pickup would not be able to run chrooted, and it may not be desirable
74141fbaed0Stron      * to use login names at all.
74241fbaed0Stron      */
74341fbaed0Stron     if (sender != 0) {
74441fbaed0Stron 	VSTRING_RESET(buf);
74541fbaed0Stron 	VSTRING_TERMINATE(buf);
74641fbaed0Stron 	tree = tok822_parse(sender);
74741fbaed0Stron 	for (naddr = 0, tp = tree; tp != 0; tp = tp->next)
74841fbaed0Stron 	    if (tp->type == TOK822_ADDR && naddr++ == 0)
74941fbaed0Stron 		tok822_internalize(buf, tp->head, TOK822_STR_DEFL);
75041fbaed0Stron 	tok822_free_tree(tree);
75141fbaed0Stron 	saved_sender = mystrdup(STR(buf));
75241fbaed0Stron 	if (naddr > 1)
75341fbaed0Stron 	    msg_warn("-f option specified malformed sender: %s", sender);
75441fbaed0Stron     } else {
75541fbaed0Stron 	if ((sender = username()) == 0)
75641fbaed0Stron 	    msg_fatal_status(EX_OSERR, "no login name found for user ID %lu",
75741fbaed0Stron 			     (unsigned long) uid);
75841fbaed0Stron 	saved_sender = mystrdup(sender);
75941fbaed0Stron     }
76041fbaed0Stron 
76141fbaed0Stron     /*
76241fbaed0Stron      * Let the postdrop command open the queue file for us, and sanity check
76341fbaed0Stron      * the content. XXX Make postdrop a manifest constant.
76441fbaed0Stron      */
76541fbaed0Stron     errno = 0;
76641fbaed0Stron     postdrop_command = vstring_alloc(1000);
76741fbaed0Stron     vstring_sprintf(postdrop_command, "%s/postdrop -r", var_command_dir);
76841fbaed0Stron     for (level = 0; level < msg_verbose; level++)
76941fbaed0Stron 	vstring_strcat(postdrop_command, " -v");
77041fbaed0Stron     if ((handle = mail_stream_command(STR(postdrop_command))) == 0)
77141fbaed0Stron 	msg_fatal_status(EX_UNAVAILABLE, "%s(%ld): unable to execute %s: %m",
77241fbaed0Stron 			 saved_sender, (long) uid, STR(postdrop_command));
77341fbaed0Stron     vstring_free(postdrop_command);
77441fbaed0Stron     dst = handle->stream;
77541fbaed0Stron 
77641fbaed0Stron     /*
77741fbaed0Stron      * First, write envelope information to the output stream.
77841fbaed0Stron      *
77941fbaed0Stron      * For sendmail compatibility, parse each command-line recipient as if it
78041fbaed0Stron      * were an RFC 822 message header; some MUAs specify comma-separated
78141fbaed0Stron      * recipient lists; and some MUAs even specify "word word <address>".
78241fbaed0Stron      *
78341fbaed0Stron      * Sort-uniq-ing the recipient list is done after address canonicalization,
78441fbaed0Stron      * before recipients are written to queue file. That's cleaner than
78541fbaed0Stron      * having the queue manager nuke duplicate recipient status records.
78641fbaed0Stron      *
78741fbaed0Stron      * XXX Should limit the size of envelope records.
78841fbaed0Stron      *
78941fbaed0Stron      * With "sendmail -N", instead of a per-message NOTIFY record we store one
79041fbaed0Stron      * per recipient so that we can simplify the implementation somewhat.
79141fbaed0Stron      */
79241fbaed0Stron     if (dsn_envid)
79341fbaed0Stron 	rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s",
79441fbaed0Stron 		    MAIL_ATTR_DSN_ENVID, dsn_envid);
795e6ca80d4Stron     if (dsn_ret)
796e6ca80d4Stron 	rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d",
797e6ca80d4Stron 		    MAIL_ATTR_DSN_RET, dsn_ret);
79841fbaed0Stron     rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s",
79941fbaed0Stron 		MAIL_ATTR_RWR_CONTEXT, rewrite_context);
80041fbaed0Stron     if (full_name || (full_name = fullname()) != 0)
80141fbaed0Stron 	rec_fputs(dst, REC_TYPE_FULL, full_name);
80241fbaed0Stron     rec_fputs(dst, REC_TYPE_FROM, saved_sender);
80341fbaed0Stron     if (verp_delims && *saved_sender == 0)
80441fbaed0Stron 	msg_fatal_status(EX_USAGE,
80541fbaed0Stron 		      "%s(%ld): -V option requires non-null sender address",
80641fbaed0Stron 			 saved_sender, (long) uid);
80741fbaed0Stron     if (encoding)
80841fbaed0Stron 	rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ENCODING, encoding);
80941fbaed0Stron     if (DEL_REQ_TRACE_FLAGS(flags))
81041fbaed0Stron 	rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_TRACE_FLAGS,
81141fbaed0Stron 		    DEL_REQ_TRACE_FLAGS(flags));
81241fbaed0Stron     if (verp_delims)
81341fbaed0Stron 	rec_fputs(dst, REC_TYPE_VERP, verp_delims);
81441fbaed0Stron     if (recipients) {
81541fbaed0Stron 	for (cpp = recipients; *cpp != 0; cpp++) {
81641fbaed0Stron 	    tree = tok822_parse(*cpp);
81741fbaed0Stron 	    for (addr_count = 0, tp = tree; tp != 0; tp = tp->next) {
81841fbaed0Stron 		if (tp->type == TOK822_ADDR) {
81941fbaed0Stron 		    tok822_internalize(buf, tp->head, TOK822_STR_DEFL);
82041fbaed0Stron 		    if (dsn_notify)
82141fbaed0Stron 			rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d",
82241fbaed0Stron 				    MAIL_ATTR_DSN_NOTIFY, dsn_notify);
82341fbaed0Stron 		    if (REC_PUT_BUF(dst, REC_TYPE_RCPT, buf) < 0)
82441fbaed0Stron 			msg_fatal_status(EX_TEMPFAIL,
82541fbaed0Stron 				    "%s(%ld): error writing queue file: %m",
82641fbaed0Stron 					 saved_sender, (long) uid);
82741fbaed0Stron 		    ++rcpt_count;
82841fbaed0Stron 		    ++addr_count;
82941fbaed0Stron 		}
83041fbaed0Stron 	    }
83141fbaed0Stron 	    tok822_free_tree(tree);
83241fbaed0Stron 	    if (addr_count == 0) {
83341fbaed0Stron 		if (rec_put(dst, REC_TYPE_RCPT, "", 0) < 0)
83441fbaed0Stron 		    msg_fatal_status(EX_TEMPFAIL,
83541fbaed0Stron 				     "%s(%ld): error writing queue file: %m",
83641fbaed0Stron 				     saved_sender, (long) uid);
83741fbaed0Stron 		++rcpt_count;
83841fbaed0Stron 	    }
83941fbaed0Stron 	}
84041fbaed0Stron     }
84141fbaed0Stron 
84241fbaed0Stron     /*
84341fbaed0Stron      * Append the message contents to the queue file. Write chunks of at most
84441fbaed0Stron      * 1kbyte. Internally, we use different record types for data ending in
84541fbaed0Stron      * LF and for data that doesn't, so we can actually be binary transparent
84641fbaed0Stron      * for local mail. Unfortunately, SMTP has no record continuation
84741fbaed0Stron      * convention, so there is no guarantee that arbitrary data will be
84841fbaed0Stron      * delivered intact via SMTP. Strip leading From_ lines. For the benefit
84941fbaed0Stron      * of UUCP environments, also get rid of leading >>>From_ lines.
85041fbaed0Stron      */
85141fbaed0Stron     rec_fputs(dst, REC_TYPE_MESG, "");
85241fbaed0Stron     if (DEL_REQ_TRACE_ONLY(flags) != 0) {
85341fbaed0Stron 	if (flags & SM_FLAG_XRCPT)
85441fbaed0Stron 	    msg_fatal_status(EX_USAGE, "%s(%ld): -t option cannot be used with -bv",
85541fbaed0Stron 			     saved_sender, (long) uid);
85641fbaed0Stron 	if (*saved_sender)
85741fbaed0Stron 	    rec_fprintf(dst, REC_TYPE_NORM, "From: %s", saved_sender);
85841fbaed0Stron 	rec_fprintf(dst, REC_TYPE_NORM, "Subject: probe");
85941fbaed0Stron 	if (recipients) {
86041fbaed0Stron 	    rec_fprintf(dst, REC_TYPE_CONT, "To:");
86141fbaed0Stron 	    for (cpp = recipients; *cpp != 0; cpp++) {
86241fbaed0Stron 		rec_fprintf(dst, REC_TYPE_NORM, "	%s%s",
86341fbaed0Stron 			    *cpp, cpp[1] ? "," : "");
86441fbaed0Stron 	    }
86541fbaed0Stron 	}
86641fbaed0Stron     } else {
86741fbaed0Stron 
86841fbaed0Stron 	/*
86941fbaed0Stron 	 * Initialize the MIME processor and set up the callback context.
87041fbaed0Stron 	 */
87141fbaed0Stron 	if (flags & SM_FLAG_XRCPT) {
87241fbaed0Stron 	    state.dst = dst;
87341fbaed0Stron 	    state.recipients = argv_alloc(2);
87441fbaed0Stron 	    state.resent_recip = argv_alloc(2);
87541fbaed0Stron 	    state.resent = 0;
87641fbaed0Stron 	    state.saved_sender = saved_sender;
87741fbaed0Stron 	    state.uid = uid;
87841fbaed0Stron 	    state.temp = vstring_alloc(10);
87941fbaed0Stron 	    mime_state = mime_state_alloc(MIME_OPT_DISABLE_MIME
88041fbaed0Stron 					  | MIME_OPT_REPORT_TRUNC_HEADER,
88141fbaed0Stron 					  output_header,
88241fbaed0Stron 					  (MIME_STATE_ANY_END) 0,
88341fbaed0Stron 					  output_text,
88441fbaed0Stron 					  (MIME_STATE_ANY_END) 0,
88541fbaed0Stron 					  (MIME_STATE_ERR_PRINT) 0,
88641fbaed0Stron 					  (void *) &state);
88741fbaed0Stron 	}
88841fbaed0Stron 
88941fbaed0Stron 	/*
89041fbaed0Stron 	 * Process header/body lines.
89141fbaed0Stron 	 */
89241fbaed0Stron 	skip_from_ = 1;
893a30b880eStron 	strip_cr = name_code(sm_fix_eol_table, NAME_CODE_FLAG_STRICT_CASE,
894a30b880eStron 			     var_sm_fix_eol);
895a30b880eStron 	if (strip_cr == STRIP_CR_ERROR)
896a30b880eStron 	    msg_fatal_status(EX_USAGE,
897a30b880eStron 		    "invalid %s value: %s", VAR_SM_FIX_EOL, var_sm_fix_eol);
89841fbaed0Stron 	for (prev_type = 0; (type = rec_streamlf_get(VSTREAM_IN, buf, var_line_limit))
89941fbaed0Stron 	     != REC_TYPE_EOF; prev_type = type) {
90041fbaed0Stron 	    if (strip_cr == STRIP_CR_DUNNO && type == REC_TYPE_NORM) {
90141fbaed0Stron 		if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
90241fbaed0Stron 		    strip_cr = STRIP_CR_DO;
90341fbaed0Stron 		else
90441fbaed0Stron 		    strip_cr = STRIP_CR_DONT;
90541fbaed0Stron 	    }
90641fbaed0Stron 	    if (skip_from_) {
90741fbaed0Stron 		if (type == REC_TYPE_NORM) {
90841fbaed0Stron 		    start = STR(buf);
90941fbaed0Stron 		    if (strncmp(start + strspn(start, ">"), "From ", 5) == 0)
91041fbaed0Stron 			continue;
91141fbaed0Stron 		}
91241fbaed0Stron 		skip_from_ = 0;
91341fbaed0Stron 	    }
91441fbaed0Stron 	    if (strip_cr == STRIP_CR_DO && type == REC_TYPE_NORM)
915a30b880eStron 		while (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
91641fbaed0Stron 		    vstring_truncate(buf, VSTRING_LEN(buf) - 1);
91741fbaed0Stron 	    if ((flags & SM_FLAG_AEOF) && prev_type != REC_TYPE_CONT
91841fbaed0Stron 		&& VSTRING_LEN(buf) == 1 && *STR(buf) == '.')
91941fbaed0Stron 		break;
92041fbaed0Stron 	    if (mime_state) {
92141fbaed0Stron 		mime_errs = mime_state_update(mime_state, type, STR(buf),
92241fbaed0Stron 					      VSTRING_LEN(buf));
92341fbaed0Stron 		if (mime_errs)
92441fbaed0Stron 		    msg_fatal_status(EX_DATAERR,
92541fbaed0Stron 				"%s(%ld): unable to extract recipients: %s",
92641fbaed0Stron 				     saved_sender, (long) uid,
92741fbaed0Stron 				     mime_state_error(mime_errs));
92841fbaed0Stron 	    } else {
92941fbaed0Stron 		if (REC_PUT_BUF(dst, type, buf) < 0)
93041fbaed0Stron 		    msg_fatal_status(EX_TEMPFAIL,
93141fbaed0Stron 				     "%s(%ld): error writing queue file: %m",
93241fbaed0Stron 				     saved_sender, (long) uid);
93341fbaed0Stron 	    }
93441fbaed0Stron 	}
93541fbaed0Stron     }
93641fbaed0Stron 
93741fbaed0Stron     /*
93841fbaed0Stron      * Finish MIME processing. We need a final mime_state_update() call in
93941fbaed0Stron      * order to flush text that is still buffered. That can happen when the
94041fbaed0Stron      * last line did not end in newline.
94141fbaed0Stron      */
94241fbaed0Stron     if (mime_state) {
94341fbaed0Stron 	mime_errs = mime_state_update(mime_state, REC_TYPE_EOF, "", 0);
94441fbaed0Stron 	if (mime_errs)
94541fbaed0Stron 	    msg_fatal_status(EX_DATAERR,
94641fbaed0Stron 			     "%s(%ld): unable to extract recipients: %s",
94741fbaed0Stron 			     saved_sender, (long) uid,
94841fbaed0Stron 			     mime_state_error(mime_errs));
94941fbaed0Stron 	mime_state = mime_state_free(mime_state);
95041fbaed0Stron     }
95141fbaed0Stron 
95241fbaed0Stron     /*
95341fbaed0Stron      * Append recipient addresses that were extracted from message headers.
95441fbaed0Stron      */
95541fbaed0Stron     rec_fputs(dst, REC_TYPE_XTRA, "");
95641fbaed0Stron     if (flags & SM_FLAG_XRCPT) {
95741fbaed0Stron 	for (cpp = state.resent ? state.resent_recip->argv :
95841fbaed0Stron 	     state.recipients->argv; *cpp; cpp++) {
95941fbaed0Stron 	    if (dsn_notify)
96041fbaed0Stron 		rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d",
96141fbaed0Stron 			    MAIL_ATTR_DSN_NOTIFY, dsn_notify);
96241fbaed0Stron 	    if (rec_put(dst, REC_TYPE_RCPT, *cpp, strlen(*cpp)) < 0)
96341fbaed0Stron 		msg_fatal_status(EX_TEMPFAIL,
96441fbaed0Stron 				 "%s(%ld): error writing queue file: %m",
96541fbaed0Stron 				 saved_sender, (long) uid);
96641fbaed0Stron 	    ++rcpt_count;
96741fbaed0Stron 	}
96841fbaed0Stron 	argv_free(state.recipients);
96941fbaed0Stron 	argv_free(state.resent_recip);
97041fbaed0Stron 	vstring_free(state.temp);
97141fbaed0Stron     }
97241fbaed0Stron     if (rcpt_count == 0)
97341fbaed0Stron 	msg_fatal_status(EX_USAGE, (flags & SM_FLAG_XRCPT) ?
97441fbaed0Stron 		 "%s(%ld): No recipient addresses found in message header" :
975e262b48eSchristos 			 "%s(%ld): Recipient addresses must be specified on"
97641fbaed0Stron 			 " the command line or via the -t option",
97741fbaed0Stron 			 saved_sender, (long) uid);
97841fbaed0Stron 
97941fbaed0Stron     /*
98041fbaed0Stron      * Identify the end of the queue file.
98141fbaed0Stron      */
98241fbaed0Stron     rec_fputs(dst, REC_TYPE_END, "");
98341fbaed0Stron 
98441fbaed0Stron     /*
98541fbaed0Stron      * Make sure that the message makes it to the file system. Once we have
98641fbaed0Stron      * terminated with successful exit status we cannot lose the message due
98741fbaed0Stron      * to "frivolous reasons". If all goes well, prevent the run-time error
98841fbaed0Stron      * handler from removing the file.
98941fbaed0Stron      */
99041fbaed0Stron     if (vstream_ferror(VSTREAM_IN))
99141fbaed0Stron 	msg_fatal_status(EX_DATAERR, "%s(%ld): error reading input: %m",
99241fbaed0Stron 			 saved_sender, (long) uid);
993*67b9b338Schristos     why = vstring_alloc(100);
994*67b9b338Schristos     if ((status = mail_stream_finish(handle, why)) != CLEANUP_STAT_OK)
99541fbaed0Stron 	msg_fatal_status((status & CLEANUP_STAT_BAD) ? EX_SOFTWARE :
99641fbaed0Stron 			 (status & CLEANUP_STAT_WRITE) ? EX_TEMPFAIL :
997*67b9b338Schristos 			 (status & CLEANUP_STAT_NOPERM) ? EX_NOPERM :
99841fbaed0Stron 			 EX_UNAVAILABLE, "%s(%ld): %s", saved_sender,
999*67b9b338Schristos 			 (long) uid, VSTRING_LEN(why) ?
1000*67b9b338Schristos 			 STR(why) : cleanup_strerror(status));
1001*67b9b338Schristos     vstring_free(why);
100241fbaed0Stron 
100341fbaed0Stron     /*
100441fbaed0Stron      * Don't leave them in the dark.
100541fbaed0Stron      */
100641fbaed0Stron     if (DEL_REQ_TRACE_FLAGS(flags)) {
100741fbaed0Stron 	vstream_printf("Mail Delivery Status Report will be mailed to <%s>.\n",
100841fbaed0Stron 		       saved_sender);
100941fbaed0Stron 	vstream_fflush(VSTREAM_OUT);
101041fbaed0Stron     }
101141fbaed0Stron 
101241fbaed0Stron     /*
101341fbaed0Stron      * Cleanup. Not really necessary as we're about to exit, but good for
101441fbaed0Stron      * debugging purposes.
101541fbaed0Stron      */
101641fbaed0Stron     vstring_free(buf);
101741fbaed0Stron     myfree(saved_sender);
101841fbaed0Stron }
101941fbaed0Stron 
102041fbaed0Stron /* tempfail - sanitize exit status after library run-time error */
102141fbaed0Stron 
tempfail(void)102241fbaed0Stron static void tempfail(void)
102341fbaed0Stron {
102441fbaed0Stron     exit(EX_TEMPFAIL);
102541fbaed0Stron }
102641fbaed0Stron 
102741fbaed0Stron MAIL_VERSION_STAMP_DECLARE;
102841fbaed0Stron 
102941fbaed0Stron /* main - the main program */
103041fbaed0Stron 
main(int argc,char ** argv)103141fbaed0Stron int     main(int argc, char **argv)
103241fbaed0Stron {
103341fbaed0Stron     static char *full_name = 0;		/* sendmail -F */
103441fbaed0Stron     struct stat st;
103541fbaed0Stron     char   *slash;
103641fbaed0Stron     char   *sender = 0;			/* sendmail -f */
103741fbaed0Stron     int     c;
103841fbaed0Stron     int     fd;
103941fbaed0Stron     int     mode;
104041fbaed0Stron     ARGV   *ext_argv;
104141fbaed0Stron     int     debug_me = 0;
104241fbaed0Stron     int     err;
104341fbaed0Stron     int     n;
104441fbaed0Stron     int     flags = SM_FLAG_DEFAULT;
104541fbaed0Stron     char   *site_to_flush = 0;
104641fbaed0Stron     char   *id_to_flush = 0;
104741fbaed0Stron     char   *encoding = 0;
104841fbaed0Stron     char   *qtime = 0;
104941fbaed0Stron     const char *errstr;
105041fbaed0Stron     uid_t   uid;
105141fbaed0Stron     const char *rewrite_context = MAIL_ATTR_RWR_LOCAL;
105241fbaed0Stron     int     dsn_notify = 0;
1053e6ca80d4Stron     int     dsn_ret = 0;
105441fbaed0Stron     const char *dsn_envid = 0;
105541fbaed0Stron     int     saved_optind;
105633881f77Schristos     ARGV   *import_env;
1057*67b9b338Schristos     char   *alias_map_from_args = 0;
105841fbaed0Stron 
105941fbaed0Stron     /*
106041fbaed0Stron      * Fingerprint executables and core dumps.
106141fbaed0Stron      */
106241fbaed0Stron     MAIL_VERSION_STAMP_ALLOCATE;
106341fbaed0Stron 
106441fbaed0Stron     /*
106541fbaed0Stron      * Be consistent with file permissions.
106641fbaed0Stron      */
106741fbaed0Stron     umask(022);
106841fbaed0Stron 
106941fbaed0Stron     /*
107041fbaed0Stron      * To minimize confusion, make sure that the standard file descriptors
107141fbaed0Stron      * are open before opening anything else. XXX Work around for 44BSD where
107241fbaed0Stron      * fstat can return EBADF on an open file descriptor.
107341fbaed0Stron      */
107441fbaed0Stron     for (fd = 0; fd < 3; fd++)
107541fbaed0Stron 	if (fstat(fd, &st) == -1
107641fbaed0Stron 	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
107741fbaed0Stron 	    msg_fatal_status(EX_OSERR, "open /dev/null: %m");
107841fbaed0Stron 
107941fbaed0Stron     /*
108041fbaed0Stron      * The CDE desktop calendar manager leaks a parent file descriptor into
108141fbaed0Stron      * the child process. For the sake of sendmail compatibility we have to
108241fbaed0Stron      * close the file descriptor otherwise mail notification will hang.
108341fbaed0Stron      */
108441fbaed0Stron     for ( /* void */ ; fd < 100; fd++)
108541fbaed0Stron 	(void) close(fd);
108641fbaed0Stron 
108741fbaed0Stron     /*
108841fbaed0Stron      * Process environment options as early as we can. We might be called
108941fbaed0Stron      * from a set-uid (set-gid) program, so be careful with importing
109041fbaed0Stron      * environment variables.
109141fbaed0Stron      */
109241fbaed0Stron     if (safe_getenv(CONF_ENV_VERB))
109341fbaed0Stron 	msg_verbose = 1;
109441fbaed0Stron     if (safe_getenv(CONF_ENV_DEBUG))
109541fbaed0Stron 	debug_me = 1;
109641fbaed0Stron 
109741fbaed0Stron     /*
109833881f77Schristos      * Initialize. Set up logging. Read the global configuration file after
109933881f77Schristos      * command-line processing. Set up signal handlers so that we can clean
110033881f77Schristos      * up incomplete output.
110141fbaed0Stron      */
110241fbaed0Stron     if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
110341fbaed0Stron 	argv[0] = slash + 1;
110441fbaed0Stron     msg_vstream_init(argv[0], VSTREAM_ERR);
110541fbaed0Stron     msg_cleanup(tempfail);
110633881f77Schristos     maillog_client_init(mail_task("sendmail"), MAILLOG_CLIENT_FLAG_NONE);
110741fbaed0Stron     set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
110841fbaed0Stron 
110941fbaed0Stron     /*
1110a30b880eStron      * Check the Postfix library version as soon as we enable logging.
1111a30b880eStron      */
1112a30b880eStron     MAIL_VERSION_CHECK;
1113a30b880eStron 
1114a30b880eStron     /*
111541fbaed0Stron      * Some sites mistakenly install Postfix sendmail as set-uid root. Drop
111641fbaed0Stron      * set-uid privileges only when root, otherwise some systems will not
111741fbaed0Stron      * reset the saved set-userid, which would be a security vulnerability.
111841fbaed0Stron      */
111941fbaed0Stron     if (geteuid() == 0 && getuid() != 0) {
112041fbaed0Stron 	msg_warn("the Postfix sendmail command has set-uid root file permissions");
112141fbaed0Stron 	msg_warn("or the command is run from a set-uid root process");
112241fbaed0Stron 	msg_warn("the Postfix sendmail command must be installed without set-uid root file permissions");
112341fbaed0Stron 	set_ugid(getuid(), getgid());
112441fbaed0Stron     }
112541fbaed0Stron 
112641fbaed0Stron     /*
112741fbaed0Stron      * Further initialization. Load main.cf first, so that command-line
112841fbaed0Stron      * options can override main.cf settings. Pre-scan the argument list so
112941fbaed0Stron      * that we load the right main.cf file.
113041fbaed0Stron      */
113141fbaed0Stron #define GETOPT_LIST "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx"
113241fbaed0Stron 
113341fbaed0Stron     saved_optind = optind;
113441fbaed0Stron     while (argv[OPTIND] != 0) {
113541fbaed0Stron 	if (strcmp(argv[OPTIND], "-q") == 0) {	/* not getopt compatible */
113641fbaed0Stron 	    optind++;
113741fbaed0Stron 	    continue;
113841fbaed0Stron 	}
113941fbaed0Stron 	if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0)
114041fbaed0Stron 	    break;
114141fbaed0Stron 	if (c == 'C') {
114241fbaed0Stron 	    VSTRING *buf = vstring_alloc(1);
114333881f77Schristos 	    char   *dir;
114441fbaed0Stron 
114533881f77Schristos 	    dir = strcmp(sane_basename(buf, optarg), MAIN_CONF_FILE) == 0 ?
114633881f77Schristos 		sane_dirname(buf, optarg) : optarg;
114733881f77Schristos 	    if (strcmp(dir, DEF_CONFIG_DIR) != 0 && geteuid() != 0)
114833881f77Schristos 		mail_conf_checkdir(dir);
114933881f77Schristos 	    if (setenv(CONF_ENV_PATH, dir, 1) < 0)
115041fbaed0Stron 		msg_fatal_status(EX_UNAVAILABLE, "out of memory");
115141fbaed0Stron 	    vstring_free(buf);
115241fbaed0Stron 	}
115341fbaed0Stron     }
115441fbaed0Stron     optind = saved_optind;
115541fbaed0Stron     mail_conf_read();
115633881f77Schristos     /* Enforce consistent operation of different Postfix parts.	 */
115733881f77Schristos     import_env = mail_parm_split(VAR_IMPORT_ENVIRON, var_import_environ);
115833881f77Schristos     update_env(import_env->argv);
115933881f77Schristos     argv_free(import_env);
1160e262b48eSchristos     /* Re-evaluate mail_task() after reading main.cf. */
116133881f77Schristos     maillog_client_init(mail_task("sendmail"), MAILLOG_CLIENT_FLAG_NONE);
116241fbaed0Stron     get_mail_conf_str_table(str_table);
116341fbaed0Stron 
116433881f77Schristos     mail_dict_init();
116533881f77Schristos 
116641fbaed0Stron     if (chdir(var_queue_dir))
116741fbaed0Stron 	msg_fatal_status(EX_UNAVAILABLE, "chdir %s: %m", var_queue_dir);
116841fbaed0Stron 
116941fbaed0Stron     signal(SIGPIPE, SIG_IGN);
117041fbaed0Stron 
117141fbaed0Stron     /*
117241fbaed0Stron      * Optionally start the debugger on ourself. This must be done after
117341fbaed0Stron      * reading the global configuration file, because that file specifies
117441fbaed0Stron      * what debugger command to execute.
117541fbaed0Stron      */
117641fbaed0Stron     if (debug_me)
117741fbaed0Stron 	debug_process();
117841fbaed0Stron 
117941fbaed0Stron     /*
118041fbaed0Stron      * The default mode of operation is determined by the process name. It
118141fbaed0Stron      * can, however, be changed via command-line options (for example,
118241fbaed0Stron      * "newaliases -bp" will show the mail queue).
118341fbaed0Stron      */
118441fbaed0Stron     if (strcmp(argv[0], "mailq") == 0) {
118541fbaed0Stron 	mode = SM_MODE_MAILQ;
118641fbaed0Stron     } else if (strcmp(argv[0], "newaliases") == 0) {
118741fbaed0Stron 	mode = SM_MODE_NEWALIAS;
118841fbaed0Stron     } else if (strcmp(argv[0], "smtpd") == 0) {
118941fbaed0Stron 	mode = SM_MODE_DAEMON;
119041fbaed0Stron     } else {
119141fbaed0Stron 	mode = SM_MODE_ENQUEUE;
119241fbaed0Stron     }
119341fbaed0Stron 
119441fbaed0Stron     /*
119541fbaed0Stron      * Parse JCL. Sendmail has been around for a long time, and has acquired
119641fbaed0Stron      * a large number of options in the course of time. Some options such as
119741fbaed0Stron      * -q are not parsable with GETOPT() and get special treatment.
119841fbaed0Stron      */
119941fbaed0Stron #define OPTIND  (optind > 0 ? optind : 1)
120041fbaed0Stron 
120141fbaed0Stron     while (argv[OPTIND] != 0) {
120241fbaed0Stron 	if (strcmp(argv[OPTIND], "-q") == 0) {
120341fbaed0Stron 	    if (mode == SM_MODE_DAEMON)
120441fbaed0Stron 		msg_warn("ignoring -q option in daemon mode");
120541fbaed0Stron 	    else
120641fbaed0Stron 		mode = SM_MODE_FLUSHQ;
120741fbaed0Stron 	    optind++;
120841fbaed0Stron 	    continue;
120941fbaed0Stron 	}
1210a30b880eStron 	if (strcmp(argv[OPTIND], "-V") == 0
1211a30b880eStron 	    && argv[OPTIND + 1] != 0 && strlen(argv[OPTIND + 1]) == 2) {
121241fbaed0Stron 	    msg_warn("option -V is deprecated with Postfix 2.3; "
121341fbaed0Stron 		     "specify -XV instead");
121441fbaed0Stron 	    argv[OPTIND] = "-XV";
121541fbaed0Stron 	}
121641fbaed0Stron 	if (strncmp(argv[OPTIND], "-V", 2) == 0 && strlen(argv[OPTIND]) == 4) {
121741fbaed0Stron 	    msg_warn("option %s is deprecated with Postfix 2.3; "
121841fbaed0Stron 		     "specify -X%s instead",
121941fbaed0Stron 		     argv[OPTIND], argv[OPTIND] + 1);
122041fbaed0Stron 	    argv[OPTIND] = concatenate("-X", argv[OPTIND] + 1, (char *) 0);
122141fbaed0Stron 	}
122241fbaed0Stron 	if (strcmp(argv[OPTIND], "-XV") == 0) {
122341fbaed0Stron 	    verp_delims = var_verp_delims;
122441fbaed0Stron 	    optind++;
122541fbaed0Stron 	    continue;
122641fbaed0Stron 	}
122741fbaed0Stron 	if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0)
122841fbaed0Stron 	    break;
122941fbaed0Stron 	switch (c) {
123041fbaed0Stron 	default:
123141fbaed0Stron 	    if (msg_verbose)
123241fbaed0Stron 		msg_info("-%c option ignored", c);
123341fbaed0Stron 	    break;
123441fbaed0Stron 	case 'n':
123541fbaed0Stron 	    msg_fatal_status(EX_USAGE, "-%c option not supported", c);
123641fbaed0Stron 	case 'B':
123741fbaed0Stron 	    if (strcmp(optarg, "8BITMIME") == 0)/* RFC 1652 */
123841fbaed0Stron 		encoding = MAIL_ATTR_ENC_8BIT;
123941fbaed0Stron 	    else if (strcmp(optarg, "7BIT") == 0)	/* RFC 1652 */
124041fbaed0Stron 		encoding = MAIL_ATTR_ENC_7BIT;
124141fbaed0Stron 	    else
124241fbaed0Stron 		msg_fatal_status(EX_USAGE, "-B option needs 8BITMIME or 7BIT");
124341fbaed0Stron 	    break;
124441fbaed0Stron 	case 'F':				/* full name */
124541fbaed0Stron 	    full_name = optarg;
124641fbaed0Stron 	    break;
124741fbaed0Stron 	case 'G':				/* gateway submission */
124841fbaed0Stron 	    rewrite_context = MAIL_ATTR_RWR_REMOTE;
124941fbaed0Stron 	    break;
125041fbaed0Stron 	case 'I':				/* newaliases */
125141fbaed0Stron 	    mode = SM_MODE_NEWALIAS;
125241fbaed0Stron 	    break;
125341fbaed0Stron 	case 'N':
125441fbaed0Stron 	    if ((dsn_notify = dsn_notify_mask(optarg)) == 0)
125541fbaed0Stron 		msg_warn("bad -N option value -- ignored");
125641fbaed0Stron 	    break;
1257e6ca80d4Stron 	case 'R':
1258e6ca80d4Stron 	    if ((dsn_ret = dsn_ret_code(optarg)) == 0)
1259e6ca80d4Stron 		msg_warn("bad -R option value -- ignored");
1260e6ca80d4Stron 	    break;
126141fbaed0Stron 	case 'V':				/* DSN, was: VERP */
126241fbaed0Stron 	    if (strlen(optarg) > 100)
126341fbaed0Stron 		msg_warn("too long -V option value -- ignored");
126441fbaed0Stron 	    else if (!allprint(optarg))
126541fbaed0Stron 		msg_warn("bad syntax in -V option value -- ignored");
126641fbaed0Stron 	    else
126741fbaed0Stron 		dsn_envid = optarg;
126841fbaed0Stron 	    break;
126941fbaed0Stron 	case 'X':
127041fbaed0Stron 	    switch (*optarg) {
127141fbaed0Stron 	    default:
127241fbaed0Stron 		msg_fatal_status(EX_USAGE, "unsupported: -%c%c", c, *optarg);
127341fbaed0Stron 	    case 'V':				/* VERP */
127441fbaed0Stron 		if (verp_delims_verify(optarg + 1) != 0)
127541fbaed0Stron 		    msg_fatal_status(EX_USAGE, "-V requires two characters from %s",
127641fbaed0Stron 				     var_verp_filter);
127741fbaed0Stron 		verp_delims = optarg + 1;
127841fbaed0Stron 		break;
127941fbaed0Stron 	    }
128041fbaed0Stron 	    break;
128141fbaed0Stron 	case 'b':
128241fbaed0Stron 	    switch (*optarg) {
128341fbaed0Stron 	    default:
128441fbaed0Stron 		msg_fatal_status(EX_USAGE, "unsupported: -%c%c", c, *optarg);
128541fbaed0Stron 	    case 'd':				/* daemon mode */
1286e6ca80d4Stron 	    case 'l':				/* daemon mode */
128741fbaed0Stron 		if (mode == SM_MODE_FLUSHQ)
128841fbaed0Stron 		    msg_warn("ignoring -q option in daemon mode");
128941fbaed0Stron 		mode = SM_MODE_DAEMON;
129041fbaed0Stron 		break;
129141fbaed0Stron 	    case 'h':				/* print host status */
129241fbaed0Stron 	    case 'H':				/* flush host status */
129341fbaed0Stron 		mode = SM_MODE_IGNORE;
129441fbaed0Stron 		break;
129541fbaed0Stron 	    case 'i':				/* newaliases */
129641fbaed0Stron 		mode = SM_MODE_NEWALIAS;
129741fbaed0Stron 		break;
129841fbaed0Stron 	    case 'm':				/* deliver mail */
129941fbaed0Stron 		mode = SM_MODE_ENQUEUE;
130041fbaed0Stron 		break;
130141fbaed0Stron 	    case 'p':				/* mailq */
130241fbaed0Stron 		mode = SM_MODE_MAILQ;
130341fbaed0Stron 		break;
130441fbaed0Stron 	    case 's':				/* stand-alone mode */
130541fbaed0Stron 		mode = SM_MODE_USER;
130641fbaed0Stron 		break;
130741fbaed0Stron 	    case 'v':				/* expand recipients */
130841fbaed0Stron 		flags |= DEL_REQ_FLAG_USR_VRFY;
130941fbaed0Stron 		break;
131041fbaed0Stron 	    }
131141fbaed0Stron 	    break;
131241fbaed0Stron 	case 'f':
131341fbaed0Stron 	    sender = optarg;
131441fbaed0Stron 	    break;
131541fbaed0Stron 	case 'i':
131641fbaed0Stron 	    flags &= ~SM_FLAG_AEOF;
131741fbaed0Stron 	    break;
131841fbaed0Stron 	case 'o':
131941fbaed0Stron 	    switch (*optarg) {
132041fbaed0Stron 	    default:
132141fbaed0Stron 		if (msg_verbose)
132241fbaed0Stron 		    msg_info("-%c%c option ignored", c, *optarg);
132341fbaed0Stron 		break;
132441fbaed0Stron 	    case 'A':
132541fbaed0Stron 		if (optarg[1] == 0)
132641fbaed0Stron 		    msg_fatal_status(EX_USAGE, "-oA requires pathname");
1327*67b9b338Schristos 		alias_map_from_args = optarg + 1;
132841fbaed0Stron 		break;
132941fbaed0Stron 	    case '7':
133041fbaed0Stron 	    case '8':
133141fbaed0Stron 		break;
133241fbaed0Stron 	    case 'i':
133341fbaed0Stron 		flags &= ~SM_FLAG_AEOF;
133441fbaed0Stron 		break;
133541fbaed0Stron 	    case 'm':
133641fbaed0Stron 		break;
133741fbaed0Stron 	    }
133841fbaed0Stron 	    break;
133941fbaed0Stron 	case 'r':				/* obsoleted by -f */
134041fbaed0Stron 	    sender = optarg;
134141fbaed0Stron 	    break;
134241fbaed0Stron 	case 'q':
134341fbaed0Stron 	    if (ISDIGIT(optarg[0])) {
134441fbaed0Stron 		qtime = optarg;
134541fbaed0Stron 	    } else if (optarg[0] == 'R') {
134641fbaed0Stron 		site_to_flush = optarg + 1;
134741fbaed0Stron 		if (*site_to_flush == 0)
134841fbaed0Stron 		    msg_fatal_status(EX_USAGE, "specify: -qRsitename");
134941fbaed0Stron 	    } else if (optarg[0] == 'I') {
135041fbaed0Stron 		id_to_flush = optarg + 1;
135141fbaed0Stron 		if (*id_to_flush == 0)
135241fbaed0Stron 		    msg_fatal_status(EX_USAGE, "specify: -qIqueueid");
135341fbaed0Stron 	    } else {
135441fbaed0Stron 		msg_fatal_status(EX_USAGE, "-q%c is not implemented",
135541fbaed0Stron 				 optarg[0]);
135641fbaed0Stron 	    }
135741fbaed0Stron 	    break;
135841fbaed0Stron 	case 't':
135941fbaed0Stron 	    flags |= SM_FLAG_XRCPT;
136041fbaed0Stron 	    break;
136141fbaed0Stron 	case 'v':
136241fbaed0Stron 	    msg_verbose++;
136341fbaed0Stron 	    break;
136441fbaed0Stron 	case '?':
136541fbaed0Stron 	    msg_fatal_status(EX_USAGE, "usage: %s [options]", argv[0]);
136641fbaed0Stron 	}
136741fbaed0Stron     }
136841fbaed0Stron 
136941fbaed0Stron     /*
137041fbaed0Stron      * Look for conflicting options and arguments.
137141fbaed0Stron      */
137241fbaed0Stron     if ((flags & SM_FLAG_XRCPT) && mode != SM_MODE_ENQUEUE)
137341fbaed0Stron 	msg_fatal_status(EX_USAGE, "-t can be used only in delivery mode");
137441fbaed0Stron 
137541fbaed0Stron     if (site_to_flush && mode != SM_MODE_ENQUEUE)
137641fbaed0Stron 	msg_fatal_status(EX_USAGE, "-qR can be used only in delivery mode");
137741fbaed0Stron 
137841fbaed0Stron     if (id_to_flush && mode != SM_MODE_ENQUEUE)
137941fbaed0Stron 	msg_fatal_status(EX_USAGE, "-qI can be used only in delivery mode");
138041fbaed0Stron 
138141fbaed0Stron     if (flags & DEL_REQ_FLAG_USR_VRFY) {
138241fbaed0Stron 	if (flags & SM_FLAG_XRCPT)
138341fbaed0Stron 	    msg_fatal_status(EX_USAGE, "-t option cannot be used with -bv");
138441fbaed0Stron 	if (dsn_notify)
138541fbaed0Stron 	    msg_fatal_status(EX_USAGE, "-N option cannot be used with -bv");
1386e6ca80d4Stron 	if (dsn_ret)
1387e6ca80d4Stron 	    msg_fatal_status(EX_USAGE, "-R option cannot be used with -bv");
138841fbaed0Stron 	if (msg_verbose == 1)
138941fbaed0Stron 	    msg_fatal_status(EX_USAGE, "-v option cannot be used with -bv");
139041fbaed0Stron     }
139141fbaed0Stron 
139241fbaed0Stron     /*
139341fbaed0Stron      * The -v option plays double duty. One requests verbose delivery, more
139441fbaed0Stron      * than one requests verbose logging.
139541fbaed0Stron      */
139641fbaed0Stron     if (msg_verbose == 1 && mode == SM_MODE_ENQUEUE) {
139741fbaed0Stron 	msg_verbose = 0;
139841fbaed0Stron 	flags |= DEL_REQ_FLAG_RECORD;
139941fbaed0Stron     }
140041fbaed0Stron 
140141fbaed0Stron     /*
140241fbaed0Stron      * Start processing. Everything is delegated to external commands.
140341fbaed0Stron      */
140441fbaed0Stron     if (qtime && mode != SM_MODE_DAEMON)
140541fbaed0Stron 	exit(0);
140641fbaed0Stron     switch (mode) {
140741fbaed0Stron     default:
140841fbaed0Stron 	msg_panic("unknown operation mode: %d", mode);
140941fbaed0Stron 	/* NOTREACHED */
141041fbaed0Stron     case SM_MODE_ENQUEUE:
141141fbaed0Stron 	if (site_to_flush) {
141241fbaed0Stron 	    if (argv[OPTIND])
141341fbaed0Stron 		msg_fatal_status(EX_USAGE, "flush site requires no recipient");
141441fbaed0Stron 	    ext_argv = argv_alloc(2);
141541fbaed0Stron 	    argv_add(ext_argv, "postqueue", "-s", site_to_flush, (char *) 0);
141641fbaed0Stron 	    for (n = 0; n < msg_verbose; n++)
141741fbaed0Stron 		argv_add(ext_argv, "-v", (char *) 0);
141841fbaed0Stron 	    argv_terminate(ext_argv);
141941fbaed0Stron 	    mail_run_replace(var_command_dir, ext_argv->argv);
142041fbaed0Stron 	    /* NOTREACHED */
142141fbaed0Stron 	} else if (id_to_flush) {
142241fbaed0Stron 	    if (argv[OPTIND])
142341fbaed0Stron 		msg_fatal_status(EX_USAGE, "flush queue_id requires no recipient");
142441fbaed0Stron 	    ext_argv = argv_alloc(2);
142541fbaed0Stron 	    argv_add(ext_argv, "postqueue", "-i", id_to_flush, (char *) 0);
142641fbaed0Stron 	    for (n = 0; n < msg_verbose; n++)
142741fbaed0Stron 		argv_add(ext_argv, "-v", (char *) 0);
142841fbaed0Stron 	    argv_terminate(ext_argv);
142941fbaed0Stron 	    mail_run_replace(var_command_dir, ext_argv->argv);
143041fbaed0Stron 	    /* NOTREACHED */
143141fbaed0Stron 	} else {
1432e6ca80d4Stron 	    enqueue(flags, encoding, dsn_envid, dsn_ret, dsn_notify,
143341fbaed0Stron 		    rewrite_context, sender, full_name, argv + OPTIND);
143441fbaed0Stron 	    exit(0);
143541fbaed0Stron 	    /* NOTREACHED */
143641fbaed0Stron 	}
143741fbaed0Stron 	break;
143841fbaed0Stron     case SM_MODE_MAILQ:
143941fbaed0Stron 	if (argv[OPTIND])
144041fbaed0Stron 	    msg_fatal_status(EX_USAGE,
144141fbaed0Stron 			     "display queue mode requires no recipient");
144241fbaed0Stron 	ext_argv = argv_alloc(2);
144341fbaed0Stron 	argv_add(ext_argv, "postqueue", "-p", (char *) 0);
144441fbaed0Stron 	for (n = 0; n < msg_verbose; n++)
144541fbaed0Stron 	    argv_add(ext_argv, "-v", (char *) 0);
144641fbaed0Stron 	argv_terminate(ext_argv);
144741fbaed0Stron 	mail_run_replace(var_command_dir, ext_argv->argv);
144841fbaed0Stron 	/* NOTREACHED */
144941fbaed0Stron     case SM_MODE_FLUSHQ:
145041fbaed0Stron 	if (argv[OPTIND])
145141fbaed0Stron 	    msg_fatal_status(EX_USAGE,
145241fbaed0Stron 			     "flush queue mode requires no recipient");
145341fbaed0Stron 	ext_argv = argv_alloc(2);
145441fbaed0Stron 	argv_add(ext_argv, "postqueue", "-f", (char *) 0);
145541fbaed0Stron 	for (n = 0; n < msg_verbose; n++)
145641fbaed0Stron 	    argv_add(ext_argv, "-v", (char *) 0);
145741fbaed0Stron 	argv_terminate(ext_argv);
145841fbaed0Stron 	mail_run_replace(var_command_dir, ext_argv->argv);
145941fbaed0Stron 	/* NOTREACHED */
146041fbaed0Stron     case SM_MODE_DAEMON:
146141fbaed0Stron 	if (argv[OPTIND])
146241fbaed0Stron 	    msg_fatal_status(EX_USAGE, "daemon mode requires no recipient");
146341fbaed0Stron 	ext_argv = argv_alloc(2);
146441fbaed0Stron 	argv_add(ext_argv, "postfix", (char *) 0);
146541fbaed0Stron 	for (n = 0; n < msg_verbose; n++)
146641fbaed0Stron 	    argv_add(ext_argv, "-v", (char *) 0);
146741fbaed0Stron 	argv_add(ext_argv, "start", (char *) 0);
146841fbaed0Stron 	argv_terminate(ext_argv);
146941fbaed0Stron 	err = (mail_run_background(var_command_dir, ext_argv->argv) < 0);
147041fbaed0Stron 	argv_free(ext_argv);
147141fbaed0Stron 	exit(err);
147241fbaed0Stron 	break;
147341fbaed0Stron     case SM_MODE_NEWALIAS:
147441fbaed0Stron 	if (argv[OPTIND])
147541fbaed0Stron 	    msg_fatal_status(EX_USAGE,
147641fbaed0Stron 			 "alias initialization mode requires no recipient");
1477*67b9b338Schristos 	if (alias_map_from_args == 0 && *var_alias_db_map == 0)
147841fbaed0Stron 	    return (0);
1479*67b9b338Schristos 	ext_argv = argv_alloc(3);
148041fbaed0Stron 	argv_add(ext_argv, "postalias", (char *) 0);
148141fbaed0Stron 	for (n = 0; n < msg_verbose; n++)
148241fbaed0Stron 	    argv_add(ext_argv, "-v", (char *) 0);
1483*67b9b338Schristos 	argv_add(ext_argv, "--", (char *) 0);
1484*67b9b338Schristos 	if (alias_map_from_args != 0)
1485*67b9b338Schristos 	    argv_add(ext_argv, alias_map_from_args, (char *) 0);
1486*67b9b338Schristos 	else
1487e262b48eSchristos 	    argv_split_append(ext_argv, var_alias_db_map, CHARS_COMMA_SP);
148841fbaed0Stron 	argv_terminate(ext_argv);
148941fbaed0Stron 	mail_run_replace(var_command_dir, ext_argv->argv);
149041fbaed0Stron 	/* NOTREACHED */
149141fbaed0Stron     case SM_MODE_USER:
149241fbaed0Stron 	if (argv[OPTIND])
149341fbaed0Stron 	    msg_fatal_status(EX_USAGE,
149441fbaed0Stron 			     "stand-alone mode requires no recipient");
149541fbaed0Stron 	/* The actual enforcement happens in the postdrop command. */
1496e262b48eSchristos 	if ((errstr = check_user_acl_byuid(VAR_SUBMIT_ACL, var_submit_acl,
1497e262b48eSchristos 					   uid = getuid())) != 0)
149841fbaed0Stron 	    msg_fatal_status(EX_NOPERM,
149941fbaed0Stron 			     "User %s(%ld) is not allowed to submit mail",
150041fbaed0Stron 			     errstr, (long) uid);
150141fbaed0Stron 	ext_argv = argv_alloc(2);
150241fbaed0Stron 	argv_add(ext_argv, "smtpd", "-S", (char *) 0);
150341fbaed0Stron 	for (n = 0; n < msg_verbose; n++)
150441fbaed0Stron 	    argv_add(ext_argv, "-v", (char *) 0);
150541fbaed0Stron 	argv_terminate(ext_argv);
150641fbaed0Stron 	mail_run_replace(var_daemon_dir, ext_argv->argv);
150741fbaed0Stron 	/* NOTREACHED */
150841fbaed0Stron     case SM_MODE_IGNORE:
150941fbaed0Stron 	exit(0);
151041fbaed0Stron 	/* NOTREACHED */
151141fbaed0Stron     }
151241fbaed0Stron }
1513