Home | History | Annotate | Line # | Download | only in pipe
      1 /*	$NetBSD: pipe.c,v 1.5 2025/02/25 19:15:47 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	pipe 8
      6 /* SUMMARY
      7 /*	Postfix delivery to external command
      8 /* SYNOPSIS
      9 /*	\fBpipe\fR [generic Postfix daemon options] command_attributes...
     10 /* DESCRIPTION
     11 /*	The \fBpipe\fR(8) daemon processes requests from the Postfix queue
     12 /*	manager to deliver messages to external commands.
     13 /*	This program expects to be run from the \fBmaster\fR(8) process
     14 /*	manager.
     15 /*
     16 /*	Message attributes such as sender address, recipient address and
     17 /*	next-hop host name can be specified as command-line macros that are
     18 /*	expanded before the external command is executed.
     19 /*
     20 /*	The \fBpipe\fR(8) daemon updates queue files and marks recipients
     21 /*	as finished, or it informs the queue manager that delivery should
     22 /*	be tried again at a later time. Delivery status reports are sent
     23 /*	to the \fBbounce\fR(8), \fBdefer\fR(8) or \fBtrace\fR(8) daemon as
     24 /*	appropriate.
     25 /* SINGLE-RECIPIENT DELIVERY
     26 /* .ad
     27 /* .fi
     28 /*	Some destinations cannot handle more than one recipient per
     29 /*	delivery request. Examples are pagers or fax machines.
     30 /*	In addition, multi-recipient delivery is undesirable when
     31 /*	prepending a \fBDelivered-to:\fR or \fBX-Original-To:\fR
     32 /*	message header.
     33 /*
     34 /*	To prevent Postfix from sending multiple recipients per delivery
     35 /*	request, specify
     36 /* .sp
     37 /* .nf
     38 /*	    \fItransport\fB_destination_recipient_limit = 1\fR
     39 /* .fi
     40 /*
     41 /*	in the Postfix \fBmain.cf\fR file, where \fItransport\fR
     42 /*	is the name in the first column of the Postfix \fBmaster.cf\fR
     43 /*	entry for the pipe-based delivery transport.
     44 /* COMMAND ATTRIBUTE SYNTAX
     45 /* .ad
     46 /* .fi
     47 /*	The external command attributes are given in the \fBmaster.cf\fR
     48 /*	file at the end of a service definition.  The syntax is as follows:
     49 /* .IP "\fBchroot=\fIpathname\fR (optional)"
     50 /*	Change the process root directory and working directory to
     51 /*	the named directory. This happens before switching to the
     52 /*	privileges specified with the \fBuser\fR attribute, and
     53 /*	before executing the optional \fBdirectory=\fIpathname\fR
     54 /*	directive. Delivery is deferred in case of failure.
     55 /* .sp
     56 /*	This feature is available as of Postfix 2.3.
     57 /* .IP "\fBdirectory=\fIpathname\fR (optional)"
     58 /*	Change to the named directory before executing the external command.
     59 /*	The directory must be accessible for the user specified with the
     60 /*	\fBuser\fR attribute (see below).
     61 /*	The default working directory is \fB$queue_directory\fR.
     62 /*	Delivery is deferred in case of failure.
     63 /* .sp
     64 /*	This feature is available as of Postfix 2.2.
     65 /* .IP "\fBeol=\fIstring\fR (optional, default: \fB\en\fR)"
     66 /*	The output record delimiter. Typically one would use either
     67 /*	\fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape
     68 /*	sequences are recognized: \fB\ea \eb \ef \en \er \et \ev
     69 /*	\e\fIddd\fR (up to three octal digits) and \fB\e\e\fR.
     70 /* .IP "\fBflags=BDFORXhqu.>\fR (optional)"
     71 /*	Optional message processing flags. By default, a message is
     72 /*	copied unchanged.
     73 /* .RS
     74 /* .IP \fBB\fR
     75 /*	Append a blank line at the end of each message. This is required
     76 /*	by some mail user agents that recognize "\fBFrom \fR" lines only
     77 /*	when preceded by a blank line.
     78 /* .IP \fBD\fR
     79 /*	Prepend a "\fBDelivered-To: \fIrecipient\fR" message header with the
     80 /*	envelope recipient address. Note: for this to work, the
     81 /*	\fItransport\fB_destination_recipient_limit\fR must be 1
     82 /*	(see SINGLE-RECIPIENT DELIVERY above for details).
     83 /* .sp
     84 /*	The \fBD\fR flag also enforces loop detection (Postfix 2.5 and later):
     85 /*	if a message already contains a \fBDelivered-To:\fR header
     86 /*	with the same recipient address, then the message is
     87 /*	returned as undeliverable. The address comparison is case
     88 /*	insensitive.
     89 /* .sp
     90 /*	This feature is available as of Postfix 2.0.
     91 /* .IP \fBF\fR
     92 /*	Prepend a "\fBFrom \fIsender time_stamp\fR" envelope header to
     93 /*	the message content.
     94 /*	This is expected by, for example, \fBUUCP\fR software.
     95 /* .IP \fBO\fR
     96 /*	Prepend an "\fBX-Original-To: \fIrecipient\fR" message header
     97 /*	with the recipient address as given to Postfix. Note: for this to
     98 /*	work, the \fItransport\fB_destination_recipient_limit\fR must be 1
     99 /*	(see SINGLE-RECIPIENT DELIVERY above for details).
    100 /* .sp
    101 /*	This feature is available as of Postfix 2.0.
    102 /* .IP \fBR\fR
    103 /*	Prepend a \fBReturn-Path:\fR message header with the envelope sender
    104 /*	address.
    105 /* .IP \fBX\fR
    106 /*	Indicate that the external command performs final delivery.
    107 /*	This flag affects the status reported in "success" DSN
    108 /*	(delivery status notification) messages, and changes it
    109 /*	from "relayed" into "delivered".
    110 /* .sp
    111 /*	This feature is available as of Postfix 2.5.
    112 /* .IP \fBh\fR
    113 /*	Fold the command-line \fB$original_recipient\fR and
    114 /*	\fB$recipient\fR address domain part
    115 /*	(text to the right of the right-most \fB@\fR character) to
    116 /*	lower case; fold the entire command-line \fB$domain\fR and
    117 /*	\fB$nexthop\fR host or domain information to lower case.
    118 /*	This is recommended for delivery via \fBUUCP\fR.
    119 /* .IP \fBq\fR
    120 /*	Quote white space and other special characters in the command-line
    121 /*	\fB$sender\fR, \fB$original_recipient\fR and \fB$recipient\fR
    122 /*	address localparts (text to the
    123 /*	left of the right-most \fB@\fR character), according to an 8-bit
    124 /*	transparent version of RFC 822.
    125 /*	This is recommended for delivery via \fBUUCP\fR or \fBBSMTP\fR.
    126 /* .sp
    127 /*	The result is compatible with the address parsing of command-line
    128 /*	recipients by the Postfix \fBsendmail\fR(1) mail submission command.
    129 /* .sp
    130 /*	The \fBq\fR flag affects only entire addresses, not the partial
    131 /*	address information from the \fB$user\fR, \fB$extension\fR or
    132 /*	\fB$mailbox\fR command-line macros.
    133 /* .IP \fBu\fR
    134 /*	Fold the command-line \fB$original_recipient\fR and
    135 /*	\fB$recipient\fR address localpart (text to
    136 /*	the left of the right-most \fB@\fR character) to lower case.
    137 /*	This is recommended for delivery via \fBUUCP\fR.
    138 /* .IP \fB.\fR
    139 /*	Prepend "\fB.\fR" to lines starting with "\fB.\fR". This is needed
    140 /*	by, for example, \fBBSMTP\fR software.
    141 /* .IP \fB>\fR
    142 /*	Prepend "\fB>\fR" to lines starting with "\fBFrom \fR". This is expected
    143 /*	by, for example, \fBUUCP\fR software.
    144 /* .RE
    145 /* .IP "\fBnull_sender\fR=\fIreplacement\fR (default: MAILER-DAEMON)"
    146 /*	Replace the null sender address (typically used for delivery
    147 /*	status notifications) with the specified text
    148 /*	when expanding the \fB$sender\fR command-line macro, and
    149 /*	when generating a From_ or Return-Path: message header.
    150 /*
    151 /*	If the null sender replacement text is a non-empty string
    152 /*	then it is affected by the \fBq\fR flag for address quoting
    153 /*	in command-line arguments.
    154 /*
    155 /*	The null sender replacement text may be empty; this form
    156 /*	is recommended for content filters that feed mail back into
    157 /*	Postfix. The empty sender address is not affected by the
    158 /*	\fBq\fR flag for address quoting in command-line arguments.
    159 /* .sp
    160 /*	Caution: a null sender address is easily mis-parsed by
    161 /*	naive software. For example, when the \fBpipe\fR(8) daemon
    162 /*	executes a command such as:
    163 /* .sp
    164 /* .nf
    165 /*	    \fIWrong\fR: command -f$sender -- $recipient
    166 /* .fi
    167 /* .IP
    168 /*	the command will mis-parse the -f option value when the
    169 /*	sender address is a null string.  For correct parsing,
    170 /*	specify \fB$sender\fR as an argument by itself:
    171 /* .sp
    172 /* .nf
    173 /*	    \fIRight\fR: command -f $sender -- $recipient
    174 /* .fi
    175 /* .IP
    176 /*	NOTE: DO NOT put quotes around the command, $sender, or $recipient.
    177 /* .IP
    178 /*	This feature is available as of Postfix 2.3.
    179 /* .IP "\fBsize\fR=\fIsize_limit\fR (optional)"
    180 /*	Don't deliver messages that exceed this size limit (in
    181 /*	bytes); return them to the sender instead.
    182 /* .IP "\fBuser\fR=\fIusername\fR (required)"
    183 /* .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
    184 /*	Execute the external command with the user ID and group ID of the
    185 /*	specified \fIusername\fR.  The software refuses to execute
    186 /*	commands with root privileges, or with the privileges of the
    187 /*	mail system owner. If \fIgroupname\fR is specified, the
    188 /*	corresponding group ID is used instead of the group ID of
    189 /*	\fIusername\fR.
    190 /* .IP "\fBargv\fR=\fIcommand\fR... (required)"
    191 /*	The command to be executed. This must be specified as the
    192 /*	last command attribute.
    193 /*	The command is executed directly, i.e. without interpretation of
    194 /*	shell meta characters by a shell command interpreter.
    195 /* .sp
    196 /*	Specify "{" and "}" around command arguments that contain
    197 /*	whitespace, arguments that begin with "{", or arguments
    198 /*	that must be an empty string (Postfix 3.0 and later). The
    199 /*	outer "{" and "}" will be removed, together with any leading
    200 /*	or trailing whitespace in the remaining text.
    201 /* .sp
    202 /*	In the command argument vector, the following macros are recognized
    203 /*	and replaced with corresponding information from the Postfix queue
    204 /*	manager delivery request.
    205 /* .sp
    206 /*	In addition to the form ${\fIname\fR}, the forms $\fIname\fR and
    207 /*	the deprecated form $(\fIname\fR) are also recognized.
    208 /*	Specify \fB$$\fR where a single \fB$\fR is wanted.
    209 /* .RS
    210 /* .IP \fB${client_address}\fR
    211 /*	This macro expands to the remote client network address.
    212 /* .sp
    213 /*	This feature is available as of Postfix 2.2.
    214 /* .IP \fB${client_helo}\fR
    215 /*	This macro expands to the remote client HELO command parameter.
    216 /* .sp
    217 /*	This feature is available as of Postfix 2.2.
    218 /* .IP \fB${client_hostname}\fR
    219 /*	This macro expands to the remote client hostname.
    220 /* .sp
    221 /*	This feature is available as of Postfix 2.2.
    222 /* .IP \fB${client_port}\fR
    223 /*	This macro expands to the remote client TCP port number.
    224 /* .sp
    225 /*	This feature is available as of Postfix 2.5.
    226 /* .IP \fB${client_protocol}\fR
    227 /*	This macro expands to the remote client protocol.
    228 /* .sp
    229 /*	This feature is available as of Postfix 2.2.
    230 /* .IP \fB${domain}\fR
    231 /*	This macro expands to the domain portion of the recipient
    232 /*	address.  For example, with an address \fIuser+foo@domain\fR
    233 /*	the domain is \fIdomain\fR.
    234 /* .sp
    235 /*	This information is modified by the \fBh\fR flag for case folding.
    236 /* .sp
    237 /*	This feature is available as of Postfix 2.5.
    238 /* .IP \fB${envid}\fR
    239 /*	This macro expands to the RFC 3461 envelope ID if available,
    240 /*	otherwise the empty string.
    241 /* .sp
    242 /*	This feature is available as of Postfix 3.9.
    243 /* .IP \fB${extension}\fR
    244 /*	This macro expands to the extension part of a recipient address.
    245 /*	For example, with an address \fIuser+foo@domain\fR the extension is
    246 /*	\fIfoo\fR.
    247 /* .sp
    248 /*	A command-line argument that contains \fB${extension}\fR expands
    249 /*	into as many command-line arguments as there are recipients.
    250 /* .sp
    251 /*	This information is modified by the \fBu\fR flag for case folding.
    252 /* .IP \fB${mailbox}\fR
    253 /*	This macro expands to the complete local part of a recipient address.
    254 /*	For example, with an address \fIuser+foo@domain\fR the mailbox is
    255 /*	\fIuser+foo\fR.
    256 /* .sp
    257 /*	A command-line argument that contains \fB${mailbox}\fR
    258 /*	expands to as many command-line arguments as there are recipients.
    259 /* .sp
    260 /*	This information is modified by the \fBu\fR flag for case folding.
    261 /* .IP \fB${nexthop}\fR
    262 /*	This macro expands to the next-hop hostname.
    263 /* .sp
    264 /*	This information is modified by the \fBh\fR flag for case folding.
    265 /* .IP \fB${original_recipient}\fR
    266 /*	This macro expands to the complete recipient address before any
    267 /*	address rewriting or aliasing.
    268 /* .sp
    269 /*	A command-line argument that contains
    270 /*	\fB${original_recipient}\fR expands to as many
    271 /*	command-line arguments as there are recipients.
    272 /* .sp
    273 /*	This information is modified by the \fBhqu\fR flags for quoting
    274 /*	and case folding.
    275 /* .sp
    276 /*	This feature is available as of Postfix 2.5.
    277 /* .IP \fB${queue_id}\fR
    278 /*	This macro expands to the queue id.
    279 /* .sp
    280 /*	This feature is available as of Postfix 2.11.
    281 /* .IP \fB${recipient}\fR
    282 /*	This macro expands to the complete recipient address.
    283 /* .sp
    284 /*	A command-line argument that contains \fB${recipient}\fR
    285 /*	expands to as many command-line arguments as there are recipients.
    286 /* .sp
    287 /*	This information is modified by the \fBhqu\fR flags for quoting
    288 /*	and case folding.
    289 /* .IP \fB${sasl_method}\fR
    290 /*	This macro expands to the name of the SASL authentication
    291 /*	mechanism in the AUTH command when the Postfix SMTP server
    292 /*	received the message.
    293 /* .sp
    294 /*	This feature is available as of Postfix 2.2.
    295 /* .IP \fB${sasl_sender}\fR
    296 /*	This macro expands to the SASL sender name (i.e. the original
    297 /*	submitter as per RFC 4954) in the MAIL FROM command when
    298 /*	the Postfix SMTP server received the message.
    299 /* .sp
    300 /*	This feature is available as of Postfix 2.2.
    301 /* .IP \fB${sasl_username}\fR
    302 /*	This macro expands to the SASL user name in the AUTH command
    303 /*	when the Postfix SMTP server received the message.
    304 /* .sp
    305 /*	This feature is available as of Postfix 2.2.
    306 /* .IP \fB${sender}\fR
    307 /*	This macro expands to the envelope sender address. By default,
    308 /*	the null sender address expands to MAILER-DAEMON; this can
    309 /*	be changed with the \fBnull_sender\fR attribute, as described
    310 /*	above.
    311 /* .sp
    312 /*	This information is modified by the \fBq\fR flag for quoting.
    313 /* .IP \fB${size}\fR
    314 /*	This macro expands to Postfix's idea of the message size, which
    315 /*	is an approximation of the size of the message as delivered.
    316 /* .IP \fB${user}\fR
    317 /*	This macro expands to the username part of a recipient address.
    318 /*	For example, with an address \fIuser+foo@domain\fR the username
    319 /*	part is \fIuser\fR.
    320 /* .sp
    321 /*	A command-line argument that contains \fB${user}\fR expands
    322 /*	into as many command-line arguments as there are recipients.
    323 /* .sp
    324 /*	This information is modified by the \fBu\fR flag for case folding.
    325 /* .RE
    326 /* STANDARDS
    327 /*	RFC 3463 (Enhanced status codes)
    328 /* DIAGNOSTICS
    329 /*	Command exit status codes are expected to
    330 /*	follow the conventions defined in <\fBsysexits.h\fR>.
    331 /*	Exit status 0 means normal successful completion.
    332 /*
    333 /*	In the case of a non-zero exit status, a limited amount of
    334 /*	command output is logged, and reported in a delivery status
    335 /*	notification.  When the output begins with a 4.X.X or 5.X.X
    336 /*	enhanced status code, the status code takes precedence over
    337 /*	the non-zero exit status (Postfix version 2.3 and later).
    338 /*
    339 /*	After successful delivery (zero exit status) a limited
    340 /*	amount of command output is logged, and reported in "success"
    341 /*	delivery status notifications (Postfix 3.0 and later).
    342 /*	This command output is not examined for the presence of an
    343 /*	enhanced status code.
    344 /*
    345 /*	Problems and transactions are logged to \fBsyslogd\fR(8)
    346 /*	or \fBpostlogd\fR(8).
    347 /*	Corrupted message files are marked so that the queue manager
    348 /*	can move them to the \fBcorrupt\fR queue for further inspection.
    349 /* SECURITY
    350 /* .fi
    351 /* .ad
    352 /*	This program needs a dual personality 1) to access the private
    353 /*	Postfix queue and IPC mechanisms, and 2) to execute external
    354 /*	commands as the specified user. It is therefore security sensitive.
    355 /* CONFIGURATION PARAMETERS
    356 /* .ad
    357 /* .fi
    358 /*	Changes to \fBmain.cf\fR are picked up automatically as \fBpipe\fR(8)
    359 /*	processes run for only a limited amount of time. Use the command
    360 /*	"\fBpostfix reload\fR" to speed up a change.
    361 /*
    362 /*	The text below provides only a parameter summary. See
    363 /*	\fBpostconf\fR(5) for more details including examples.
    364 /* RESOURCE AND RATE CONTROLS
    365 /* .ad
    366 /* .fi
    367 /*	In the text below, \fItransport\fR is the first field in a
    368 /*	\fBmaster.cf\fR entry.
    369 /* .IP "\fBtransport_time_limit ($command_time_limit)\fR"
    370 /*	A transport-specific override for the command_time_limit parameter
    371 /*	value, where \fItransport\fR is the master.cf name of the message
    372 /*	delivery transport.
    373 /* .PP
    374 /*	Implemented in the qmgr(8) daemon:
    375 /* .IP "\fBtransport_destination_concurrency_limit ($default_destination_concurrency_limit)\fR"
    376 /*	A transport-specific override for the
    377 /*	default_destination_concurrency_limit parameter value, where
    378 /*	\fItransport\fR is the master.cf name of the message delivery
    379 /*	transport.
    380 /* .IP "\fBtransport_destination_recipient_limit ($default_destination_recipient_limit)\fR"
    381 /*	A transport-specific override for the
    382 /*	default_destination_recipient_limit parameter value, where
    383 /*	\fItransport\fR is the master.cf name of the message delivery
    384 /*	transport.
    385 /* MISCELLANEOUS CONTROLS
    386 /* .ad
    387 /* .fi
    388 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
    389 /*	The default location of the Postfix main.cf and master.cf
    390 /*	configuration files.
    391 /* .IP "\fBdaemon_timeout (18000s)\fR"
    392 /*	How much time a Postfix daemon process may take to handle a
    393 /*	request before it is terminated by a built-in watchdog timer.
    394 /* .IP "\fBdelay_logging_resolution_limit (2)\fR"
    395 /*	The maximal number of digits after the decimal point when logging
    396 /*	delay values.
    397 /* .IP "\fBexport_environment (see 'postconf -d' output)\fR"
    398 /*	The list of environment variables that a Postfix process will export
    399 /*	to non-Postfix processes.
    400 /* .IP "\fBipc_timeout (3600s)\fR"
    401 /*	The time limit for sending or receiving information over an internal
    402 /*	communication channel.
    403 /* .IP "\fBmail_owner (postfix)\fR"
    404 /*	The UNIX system account that owns the Postfix queue and most Postfix
    405 /*	daemon processes.
    406 /* .IP "\fBmax_idle (100s)\fR"
    407 /*	The maximum amount of time that an idle Postfix daemon process waits
    408 /*	for an incoming connection before terminating voluntarily.
    409 /* .IP "\fBmax_use (100)\fR"
    410 /*	The maximal number of incoming connections that a Postfix daemon
    411 /*	process will service before terminating voluntarily.
    412 /* .IP "\fBprocess_id (read-only)\fR"
    413 /*	The process ID of a Postfix command or daemon process.
    414 /* .IP "\fBprocess_name (read-only)\fR"
    415 /*	The process name of a Postfix command or daemon process.
    416 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
    417 /*	The location of the Postfix top-level queue directory.
    418 /* .IP "\fBrecipient_delimiter (empty)\fR"
    419 /*	The set of characters that can separate an email address
    420 /*	localpart, user name, or a .forward file name from its extension.
    421 /* .IP "\fBsyslog_facility (mail)\fR"
    422 /*	The syslog facility of Postfix logging.
    423 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
    424 /*	A prefix that is prepended to the process name in syslog
    425 /*	records, so that, for example, "smtpd" becomes "prefix/smtpd".
    426 /* .PP
    427 /*	Available in Postfix version 3.0 and later:
    428 /* .IP "\fBpipe_delivery_status_filter ($default_delivery_status_filter)\fR"
    429 /*	Optional filter for the \fBpipe\fR(8) delivery agent to change the
    430 /*	delivery status code or explanatory text of successful or unsuccessful
    431 /*	deliveries.
    432 /* .PP
    433 /*	Available in Postfix version 3.3 and later:
    434 /* .IP "\fBenable_original_recipient (yes)\fR"
    435 /*	Enable support for the original recipient address after an
    436 /*	address is rewritten to a different address (for example with
    437 /*	aliasing or with canonical mapping).
    438 /* .IP "\fBservice_name (read-only)\fR"
    439 /*	The master.cf service name of a Postfix daemon process.
    440 /* .PP
    441 /*	Available in Postfix 3.5 and later:
    442 /* .IP "\fBinfo_log_address_format (external)\fR"
    443 /*	The email address form that will be used in non-debug logging
    444 /*	(info, warning, etc.).
    445 /* SEE ALSO
    446 /*	qmgr(8), queue manager
    447 /*	bounce(8), delivery status reports
    448 /*	postconf(5), configuration parameters
    449 /*	master(5), generic daemon options
    450 /*	master(8), process manager
    451 /*	postlogd(8), Postfix logging
    452 /*	syslogd(8), system logging
    453 /* LICENSE
    454 /* .ad
    455 /* .fi
    456 /*	The Secure Mailer license must be distributed with this software.
    457 /* AUTHOR(S)
    458 /*	Wietse Venema
    459 /*	IBM T.J. Watson Research
    460 /*	P.O. Box 704
    461 /*	Yorktown Heights, NY 10598, USA
    462 /*
    463 /*	Wietse Venema
    464 /*	Google, Inc.
    465 /*	111 8th Avenue
    466 /*	New York, NY 10011, USA
    467 /*--*/
    468 
    469 /* System library. */
    470 
    471 #include <sys_defs.h>
    472 #include <unistd.h>
    473 #include <stdlib.h>
    474 #include <string.h>
    475 #include <pwd.h>
    476 #include <grp.h>
    477 #include <fcntl.h>
    478 #include <ctype.h>
    479 
    480 #ifdef STRCASECMP_IN_STRINGS_H
    481 #include <strings.h>
    482 #endif
    483 
    484 /* Utility library. */
    485 
    486 #include <msg.h>
    487 #include <vstream.h>
    488 #include <vstring.h>
    489 #include <argv.h>
    490 #include <htable.h>
    491 #include <dict.h>
    492 #include <iostuff.h>
    493 #include <mymalloc.h>
    494 #include <mac_parse.h>
    495 #include <set_eugid.h>
    496 #include <split_at.h>
    497 #include <stringops.h>
    498 
    499 /* Global library. */
    500 
    501 #include <recipient_list.h>
    502 #include <deliver_request.h>
    503 #include <mail_params.h>
    504 #include <mail_version.h>
    505 #include <mail_conf.h>
    506 #include <bounce.h>
    507 #include <defer.h>
    508 #include <deliver_completed.h>
    509 #include <sent.h>
    510 #include <pipe_command.h>
    511 #include <mail_copy.h>
    512 #include <mail_addr.h>
    513 #include <canon_addr.h>
    514 #include <split_addr.h>
    515 #include <off_cvt.h>
    516 #include <quote_822_local.h>
    517 #include <flush_clnt.h>
    518 #include <dsn_util.h>
    519 #include <dsn_buf.h>
    520 #include <sys_exits.h>
    521 #include <delivered_hdr.h>
    522 #include <fold_addr.h>
    523 #include <mail_parm_split.h>
    524 
    525 /* Single server skeleton. */
    526 
    527 #include <mail_server.h>
    528 
    529 /* Application-specific. */
    530 
    531  /*
    532   * The mini symbol table name and keys used for expanding macros in
    533   * command-line arguments.
    534   *
    535   * XXX Update  the parse_callback() routine when something gets added here,
    536   * even when the macro is not recipient dependent.
    537   */
    538 #define PIPE_DICT_TABLE		"pipe_command"	/* table name */
    539 #define PIPE_DICT_NEXTHOP	"nexthop"	/* key */
    540 #define PIPE_DICT_RCPT		"recipient"	/* key */
    541 #define PIPE_DICT_ORIG_RCPT	"original_recipient"	/* key */
    542 #define PIPE_DICT_SENDER	"sender"/* key */
    543 #define PIPE_DICT_USER		"user"	/* key */
    544 #define PIPE_DICT_EXTENSION	"extension"	/* key */
    545 #define PIPE_DICT_MAILBOX	"mailbox"	/* key */
    546 #define PIPE_DICT_DOMAIN	"domain"/* key */
    547 #define PIPE_DICT_SIZE		"size"	/* key */
    548 #define PIPE_DICT_CLIENT_ADDR	"client_address"	/* key */
    549 #define PIPE_DICT_CLIENT_NAME	"client_hostname"	/* key */
    550 #define PIPE_DICT_CLIENT_PORT	"client_port"	/* key */
    551 #define PIPE_DICT_CLIENT_PROTO	"client_protocol"	/* key */
    552 #define PIPE_DICT_CLIENT_HELO	"client_helo"	/* key */
    553 #define PIPE_DICT_SASL_METHOD	"sasl_method"	/* key */
    554 #define PIPE_DICT_SASL_USERNAME	"sasl_username"	/* key */
    555 #define PIPE_DICT_SASL_SENDER	"sasl_sender"	/* key */
    556 #define PIPE_DICT_QUEUE_ID	"queue_id"	/* key */
    557 #define PIPE_DICT_ENVID		"envid"	/* key */
    558 
    559  /*
    560   * Flags used to pass back the type of special parameter found by
    561   * parse_callback.
    562   */
    563 #define PIPE_FLAG_RCPT		(1<<0)
    564 #define PIPE_FLAG_USER		(1<<1)
    565 #define PIPE_FLAG_EXTENSION	(1<<2)
    566 #define PIPE_FLAG_MAILBOX	(1<<3)
    567 #define PIPE_FLAG_DOMAIN	(1<<4)
    568 #define PIPE_FLAG_ORIG_RCPT	(1<<5)
    569 
    570  /*
    571   * Additional flags. These are colocated with mail_copy() flags. Allow some
    572   * space for extension of the mail_copy() interface.
    573   */
    574 #define PIPE_OPT_FOLD_BASE	(16)
    575 #define PIPE_OPT_FOLD_USER	(FOLD_ADDR_USER << PIPE_OPT_FOLD_BASE)
    576 #define PIPE_OPT_FOLD_HOST	(FOLD_ADDR_HOST << PIPE_OPT_FOLD_BASE)
    577 #define PIPE_OPT_QUOTE_LOCAL	(1 << (PIPE_OPT_FOLD_BASE + 2))
    578 #define PIPE_OPT_FINAL_DELIVERY	(1 << (PIPE_OPT_FOLD_BASE + 3))
    579 
    580 #define PIPE_OPT_FOLD_ALL	(FOLD_ADDR_ALL << PIPE_OPT_FOLD_BASE)
    581 #define PIPE_OPT_FOLD_FLAGS(f) \
    582 	(((f) & PIPE_OPT_FOLD_ALL) >> PIPE_OPT_FOLD_BASE)
    583 
    584  /*
    585   * Tunable parameters. Values are taken from the config file, after
    586   * prepending the service name to _name, and so on.
    587   */
    588 int     var_command_maxtime;		/* You can now leave this here. */
    589 
    590  /*
    591   * Other main.cf parameters.
    592   */
    593 char   *var_pipe_dsn_filter;
    594 
    595  /*
    596   * For convenience. Instead of passing around lists of parameters, bundle
    597   * them up in convenient structures.
    598   */
    599 
    600  /*
    601   * Structure for service-specific configuration parameters.
    602   */
    603 typedef struct {
    604     int     time_limit;			/* per-service time limit */
    605 } PIPE_PARAMS;
    606 
    607  /*
    608   * Structure for command-line parameters.
    609   */
    610 typedef struct {
    611     char  **command;			/* argument vector */
    612     uid_t   uid;			/* command privileges */
    613     gid_t   gid;			/* command privileges */
    614     int     flags;			/* mail_copy() flags */
    615     char   *exec_dir;			/* working directory */
    616     char   *chroot_dir;			/* chroot directory */
    617     VSTRING *eol;			/* output record delimiter */
    618     VSTRING *null_sender;		/* null sender expansion */
    619     off_t   size_limit;			/* max size in bytes we will accept */
    620 } PIPE_ATTR;
    621 
    622  /*
    623   * Structure for command-line parameter macro expansion.
    624   */
    625 typedef struct {
    626     const char *service;		/* for warnings */
    627     int     expand_flag;		/* callback result */
    628 } PIPE_STATE;
    629 
    630  /*
    631   * Silly little macros.
    632   */
    633 #define STR	vstring_str
    634 
    635 /* parse_callback - callback for mac_parse() */
    636 
    637 static int parse_callback(int type, VSTRING *buf, void *context)
    638 {
    639     PIPE_STATE *state = (PIPE_STATE *) context;
    640     struct cmd_flags {
    641 	const char *name;
    642 	int     flags;
    643     };
    644     static struct cmd_flags cmd_flags[] = {
    645 	PIPE_DICT_NEXTHOP, 0,
    646 	PIPE_DICT_RCPT, PIPE_FLAG_RCPT,
    647 	PIPE_DICT_ORIG_RCPT, PIPE_FLAG_ORIG_RCPT,
    648 	PIPE_DICT_SENDER, 0,
    649 	PIPE_DICT_USER, PIPE_FLAG_USER,
    650 	PIPE_DICT_EXTENSION, PIPE_FLAG_EXTENSION,
    651 	PIPE_DICT_MAILBOX, PIPE_FLAG_MAILBOX,
    652 	PIPE_DICT_DOMAIN, PIPE_FLAG_DOMAIN,
    653 	PIPE_DICT_SIZE, 0,
    654 	PIPE_DICT_CLIENT_ADDR, 0,
    655 	PIPE_DICT_CLIENT_NAME, 0,
    656 	PIPE_DICT_CLIENT_PORT, 0,
    657 	PIPE_DICT_CLIENT_PROTO, 0,
    658 	PIPE_DICT_CLIENT_HELO, 0,
    659 	PIPE_DICT_SASL_METHOD, 0,
    660 	PIPE_DICT_SASL_USERNAME, 0,
    661 	PIPE_DICT_SASL_SENDER, 0,
    662 	PIPE_DICT_QUEUE_ID, 0,
    663 	PIPE_DICT_ENVID, 0,
    664 	0, 0,
    665     };
    666     struct cmd_flags *p;
    667 
    668     /*
    669      * See if this command-line argument references a special macro.
    670      */
    671     if (type == MAC_PARSE_VARNAME) {
    672 	for (p = cmd_flags; /* see below */ ; p++) {
    673 	    if (p->name == 0) {
    674 		msg_warn("file %s/%s: service %s: unknown macro name: \"%s\"",
    675 			 var_config_dir, MASTER_CONF_FILE,
    676 			 state->service, vstring_str(buf));
    677 		return (MAC_PARSE_ERROR);
    678 	    } else if (strcmp(vstring_str(buf), p->name) == 0) {
    679 		state->expand_flag |= p->flags;
    680 		return (0);
    681 	    }
    682 	}
    683     }
    684     return (0);
    685 }
    686 
    687 /* morph_recipient - morph a recipient address */
    688 
    689 static void morph_recipient(VSTRING *buf, const char *address, int flags)
    690 {
    691     VSTRING *temp = vstring_alloc(100);
    692 
    693     /*
    694      * Quote the recipient address as appropriate.
    695      */
    696     if (flags & PIPE_OPT_QUOTE_LOCAL)
    697 	quote_822_local(temp, address);
    698     else
    699 	vstring_strcpy(temp, address);
    700 
    701     /*
    702      * Fold the recipient address as appropriate.
    703      */
    704     fold_addr(buf, STR(temp), PIPE_OPT_FOLD_FLAGS(flags));
    705 
    706     vstring_free(temp);
    707 }
    708 
    709 /* expand_argv - expand macros in the argument vector */
    710 
    711 static ARGV *expand_argv(const char *service, char **argv,
    712 			         RECIPIENT_LIST *rcpt_list, int flags)
    713 {
    714     VSTRING *buf = vstring_alloc(100);
    715     ARGV   *result;
    716     char  **cpp;
    717     PIPE_STATE state;
    718     int     i;
    719     char   *ext;
    720     char   *dom;
    721 
    722     /*
    723      * This appears to be simple operation (replace $name by its expansion).
    724      * However, it becomes complex because a command-line argument that
    725      * references $recipient must expand to as many command-line arguments as
    726      * there are recipients (that's wat programs called by sendmail expect).
    727      * So we parse each command-line argument, and depending on what we find,
    728      * we either expand the argument just once, or we expand it once for each
    729      * recipient. In either case we end up parsing the command-line argument
    730      * twice. The amount of CPU time wasted will be negligible.
    731      *
    732      * Note: we can't use recursive macro expansion here, because recursion
    733      * would screw up mail addresses that contain $ characters.
    734      */
    735 #define NO	0
    736 #define EARLY_RETURN(x) { argv_free(result); vstring_free(buf); return (x); }
    737 
    738     result = argv_alloc(1);
    739     for (cpp = argv; *cpp; cpp++) {
    740 	state.service = service;
    741 	state.expand_flag = 0;
    742 	if (mac_parse(*cpp, parse_callback, (void *) &state) & MAC_PARSE_ERROR)
    743 	    EARLY_RETURN(0);
    744 	if (state.expand_flag == 0) {		/* no $recipient etc. */
    745 	    argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END);
    746 	} else {				/* contains $recipient etc. */
    747 	    for (i = 0; i < rcpt_list->len; i++) {
    748 
    749 		/*
    750 		 * This argument contains $recipient.
    751 		 */
    752 		if (state.expand_flag & PIPE_FLAG_RCPT) {
    753 		    morph_recipient(buf, rcpt_list->info[i].address, flags);
    754 		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_RCPT, STR(buf));
    755 		}
    756 
    757 		/*
    758 		 * This argument contains $original_recipient.
    759 		 */
    760 		if (state.expand_flag & PIPE_FLAG_ORIG_RCPT) {
    761 		    morph_recipient(buf, rcpt_list->info[i].orig_addr, flags);
    762 		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_ORIG_RCPT, STR(buf));
    763 		}
    764 
    765 		/*
    766 		 * This argument contains $user. Extract the plain user name.
    767 		 * Either anything to the left of the extension delimiter or,
    768 		 * in absence of the latter, anything to the left of the
    769 		 * rightmost @.
    770 		 *
    771 		 * Beware: if the user name is blank (e.g. +user@host), the
    772 		 * argument is suppressed. This is necessary to allow for
    773 		 * cyrus bulletin-board (global mailbox) delivery. XXX But,
    774 		 * skipping empty user parts will also prevent other
    775 		 * expansions of this specific command-line argument.
    776 		 */
    777 		if (state.expand_flag & PIPE_FLAG_USER) {
    778 		    morph_recipient(buf, rcpt_list->info[i].address,
    779 				    flags & PIPE_OPT_FOLD_ALL);
    780 		    if (split_at_right(STR(buf), '@') == 0)
    781 			msg_warn("no @ in recipient address: %s",
    782 				 rcpt_list->info[i].address);
    783 		    if (*var_rcpt_delim)
    784 			split_addr(STR(buf), var_rcpt_delim);
    785 		    if (*STR(buf) == 0)
    786 			continue;
    787 		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf));
    788 		}
    789 
    790 		/*
    791 		 * This argument contains $extension. Extract the recipient
    792 		 * extension: anything between the leftmost extension
    793 		 * delimiter and the rightmost @. The extension may be blank.
    794 		 */
    795 		if (state.expand_flag & PIPE_FLAG_EXTENSION) {
    796 		    morph_recipient(buf, rcpt_list->info[i].address,
    797 				    flags & PIPE_OPT_FOLD_ALL);
    798 		    if (split_at_right(STR(buf), '@') == 0)
    799 			msg_warn("no @ in recipient address: %s",
    800 				 rcpt_list->info[i].address);
    801 		    if (*var_rcpt_delim == 0
    802 			|| (ext = split_addr(STR(buf), var_rcpt_delim)) == 0)
    803 			ext = "";		/* insert null arg */
    804 		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext);
    805 		}
    806 
    807 		/*
    808 		 * This argument contains $mailbox. Extract the mailbox name:
    809 		 * anything to the left of the rightmost @.
    810 		 */
    811 		if (state.expand_flag & PIPE_FLAG_MAILBOX) {
    812 		    morph_recipient(buf, rcpt_list->info[i].address,
    813 				    flags & PIPE_OPT_FOLD_ALL);
    814 		    if (split_at_right(STR(buf), '@') == 0)
    815 			msg_warn("no @ in recipient address: %s",
    816 				 rcpt_list->info[i].address);
    817 		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_MAILBOX, STR(buf));
    818 		}
    819 
    820 		/*
    821 		 * This argument contains $domain. Extract the domain name:
    822 		 * anything to the right of the rightmost @.
    823 		 */
    824 		if (state.expand_flag & PIPE_FLAG_DOMAIN) {
    825 		    morph_recipient(buf, rcpt_list->info[i].address,
    826 				    flags & PIPE_OPT_FOLD_ALL);
    827 		    dom = split_at_right(STR(buf), '@');
    828 		    if (dom == 0) {
    829 			msg_warn("no @ in recipient address: %s",
    830 				 rcpt_list->info[i].address);
    831 			dom = "";		/* insert null arg */
    832 		    }
    833 		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_DOMAIN, dom);
    834 		}
    835 
    836 		/*
    837 		 * Done.
    838 		 */
    839 		argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END);
    840 	    }
    841 	}
    842     }
    843     argv_terminate(result);
    844     vstring_free(buf);
    845     return (result);
    846 }
    847 
    848 /* get_service_params - get service-name dependent config information */
    849 
    850 static void get_service_params(PIPE_PARAMS *config, char *service)
    851 {
    852     const char *myname = "get_service_params";
    853 
    854     /*
    855      * Figure out the command time limit for this transport.
    856      */
    857     config->time_limit =
    858 	get_mail_conf_time2(service, _MAXTIME, var_command_maxtime, 's', 1, 0);
    859 
    860     /*
    861      * Give the poor tester a clue of what is going on.
    862      */
    863     if (msg_verbose)
    864 	msg_info("%s: time_limit %d", myname, config->time_limit);
    865 }
    866 
    867 /* get_service_attr - get command-line attributes */
    868 
    869 static void get_service_attr(PIPE_ATTR *attr, char **argv)
    870 {
    871     const char *myname = "get_service_attr";
    872     struct passwd *pwd;
    873     struct group *grp;
    874     char   *user;			/* user name */
    875     char   *group;			/* group name */
    876     char   *size;			/* max message size */
    877     char   *cp;
    878 
    879     /*
    880      * Initialize.
    881      */
    882     user = 0;
    883     group = 0;
    884     attr->command = 0;
    885     attr->flags = 0;
    886     attr->exec_dir = 0;
    887     attr->chroot_dir = 0;
    888     attr->eol = vstring_strcpy(vstring_alloc(1), "\n");
    889     attr->null_sender = vstring_strcpy(vstring_alloc(1), MAIL_ADDR_MAIL_DAEMON);
    890     attr->size_limit = 0;
    891 
    892     /*
    893      * Iterate over the command-line attribute list.
    894      */
    895     for ( /* void */ ; *argv != 0; argv++) {
    896 
    897 	/*
    898 	 * flags=stuff
    899 	 */
    900 	if (strncasecmp("flags=", *argv, sizeof("flags=") - 1) == 0) {
    901 	    for (cp = *argv + sizeof("flags=") - 1; *cp; cp++) {
    902 		switch (*cp) {
    903 		case 'B':
    904 		    attr->flags |= MAIL_COPY_BLANK;
    905 		    break;
    906 		case 'D':
    907 		    attr->flags |= MAIL_COPY_DELIVERED;
    908 		    break;
    909 		case 'F':
    910 		    attr->flags |= MAIL_COPY_FROM;
    911 		    break;
    912 		case 'O':
    913 		    attr->flags |= MAIL_COPY_ORIG_RCPT;
    914 		    break;
    915 		case 'R':
    916 		    attr->flags |= MAIL_COPY_RETURN_PATH;
    917 		    break;
    918 		case 'X':
    919 		    attr->flags |= PIPE_OPT_FINAL_DELIVERY;
    920 		    break;
    921 		case '.':
    922 		    attr->flags |= MAIL_COPY_DOT;
    923 		    break;
    924 		case '>':
    925 		    attr->flags |= MAIL_COPY_QUOTE;
    926 		    break;
    927 		case 'h':
    928 		    attr->flags |= PIPE_OPT_FOLD_HOST;
    929 		    break;
    930 		case 'q':
    931 		    attr->flags |= PIPE_OPT_QUOTE_LOCAL;
    932 		    break;
    933 		case 'u':
    934 		    attr->flags |= PIPE_OPT_FOLD_USER;
    935 		    break;
    936 		default:
    937 		    msg_fatal("unknown flag: %c (ignored)", *cp);
    938 		    break;
    939 		}
    940 	    }
    941 	}
    942 
    943 	/*
    944 	 * user=username[:groupname]
    945 	 */
    946 	else if (strncasecmp("user=", *argv, sizeof("user=") - 1) == 0) {
    947 	    user = *argv + sizeof("user=") - 1;
    948 	    if ((group = split_at(user, ':')) != 0)	/* XXX clobbers argv */
    949 		if (*group == 0)
    950 		    group = 0;
    951 	    if ((pwd = getpwnam(user)) == 0)
    952 		msg_fatal("%s: unknown username: %s", myname, user);
    953 	    attr->uid = pwd->pw_uid;
    954 	    if (group != 0) {
    955 		if ((grp = getgrnam(group)) == 0)
    956 		    msg_fatal("%s: unknown group: %s", myname, group);
    957 		attr->gid = grp->gr_gid;
    958 	    } else {
    959 		attr->gid = pwd->pw_gid;
    960 	    }
    961 	}
    962 
    963 	/*
    964 	 * directory=string
    965 	 */
    966 	else if (strncasecmp("directory=", *argv, sizeof("directory=") - 1) == 0) {
    967 	    attr->exec_dir = mystrdup(*argv + sizeof("directory=") - 1);
    968 	}
    969 
    970 	/*
    971 	 * chroot=string
    972 	 */
    973 	else if (strncasecmp("chroot=", *argv, sizeof("chroot=") - 1) == 0) {
    974 	    attr->chroot_dir = mystrdup(*argv + sizeof("chroot=") - 1);
    975 	}
    976 
    977 	/*
    978 	 * eol=string
    979 	 */
    980 	else if (strncasecmp("eol=", *argv, sizeof("eol=") - 1) == 0) {
    981 	    unescape(attr->eol, *argv + sizeof("eol=") - 1);
    982 	}
    983 
    984 	/*
    985 	 * null_sender=string
    986 	 */
    987 	else if (strncasecmp("null_sender=", *argv, sizeof("null_sender=") - 1) == 0) {
    988 	    vstring_strcpy(attr->null_sender, *argv + sizeof("null_sender=") - 1);
    989 	}
    990 
    991 	/*
    992 	 * size=max_message_size (in bytes)
    993 	 */
    994 	else if (strncasecmp("size=", *argv, sizeof("size=") - 1) == 0) {
    995 	    size = *argv + sizeof("size=") - 1;
    996 	    if ((attr->size_limit = off_cvt_string(size)) < 0)
    997 		msg_fatal("%s: bad size= value: %s", myname, size);
    998 	}
    999 
   1000 	/*
   1001 	 * argv=command...
   1002 	 */
   1003 	else if (strncasecmp("argv=", *argv, sizeof("argv=") - 1) == 0) {
   1004 	    *argv += sizeof("argv=") - 1;	/* XXX clobbers argv */
   1005 	    attr->command = argv;
   1006 	    break;
   1007 	}
   1008 
   1009 	/*
   1010 	 * Bad.
   1011 	 */
   1012 	else
   1013 	    msg_fatal("unknown attribute name: %s", *argv);
   1014     }
   1015 
   1016     /*
   1017      * Sanity checks. Verify that every member has an acceptable value.
   1018      */
   1019     if (user == 0)
   1020 	msg_fatal("missing user= command-line attribute");
   1021     if (attr->command == 0)
   1022 	msg_fatal("missing argv= command-line attribute");
   1023     if (attr->uid == 0)
   1024 	msg_fatal("user= command-line attribute specifies root privileges");
   1025     if (attr->uid == var_owner_uid)
   1026 	msg_fatal("user= command-line attribute specifies mail system owner %s",
   1027 		  var_mail_owner);
   1028     if (attr->gid == 0)
   1029 	msg_fatal("user= command-line attribute specifies privileged group id 0");
   1030     if (attr->gid == var_owner_gid)
   1031 	msg_fatal("user= command-line attribute specifies mail system owner %s group id %ld",
   1032 		  var_mail_owner, (long) attr->gid);
   1033     if (attr->gid == var_sgid_gid)
   1034 	msg_fatal("user= command-line attribute specifies mail system %s group id %ld",
   1035 		  var_sgid_group, (long) attr->gid);
   1036 
   1037     /*
   1038      * Give the poor tester a clue of what is going on.
   1039      */
   1040     if (msg_verbose)
   1041 	msg_info("%s: uid %ld, gid %ld, flags %d, size %ld",
   1042 		 myname, (long) attr->uid, (long) attr->gid,
   1043 		 attr->flags, (long) attr->size_limit);
   1044 }
   1045 
   1046 /* eval_command_status - do something with command completion status */
   1047 
   1048 static int eval_command_status(int command_status, char *service,
   1049 			          DELIVER_REQUEST *request, PIPE_ATTR *attr,
   1050 			               DSN_BUF *why)
   1051 {
   1052     RECIPIENT *rcpt;
   1053     int     status;
   1054     int     result = 0;
   1055     int     n;
   1056     char   *saved_text;
   1057 
   1058     /*
   1059      * Depending on the result, bounce or defer the message, and mark the
   1060      * recipient as done where appropriate.
   1061      */
   1062     switch (command_status) {
   1063     case PIPE_STAT_OK:
   1064 	/* Save the command output before dsb_update() clobbers it. */
   1065 	vstring_truncate(why->reason, trimblanks(STR(why->reason),
   1066 			      VSTRING_LEN(why->reason)) - STR(why->reason));
   1067 	if (VSTRING_LEN(why->reason) > 0) {
   1068 	    VSTRING_TERMINATE(why->reason);
   1069 	    saved_text =
   1070 		vstring_export(vstring_sprintf(
   1071 				    vstring_alloc(VSTRING_LEN(why->reason)),
   1072 					    " (%.100s)", STR(why->reason)));
   1073 	} else
   1074 	    saved_text = mystrdup("");		/* uses shared R/O storage */
   1075 	dsb_update(why, "2.0.0", (attr->flags & PIPE_OPT_FINAL_DELIVERY) ?
   1076 		   "delivered" : "relayed", DSB_SKIP_RMTA, DSB_SKIP_REPLY,
   1077 		   "delivered via %s service%s", service, saved_text);
   1078 	myfree(saved_text);
   1079 	(void) DSN_FROM_DSN_BUF(why);
   1080 	for (n = 0; n < request->rcpt_list.len; n++) {
   1081 	    rcpt = request->rcpt_list.info + n;
   1082 	    status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
   1083 			  request->queue_id, &request->msg_stats, rcpt,
   1084 			  service, &why->dsn);
   1085 	    if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
   1086 		deliver_completed(request->fp, rcpt->offset);
   1087 	    result |= status;
   1088 	}
   1089 	break;
   1090     case PIPE_STAT_BOUNCE:
   1091     case PIPE_STAT_DEFER:
   1092 	(void) DSN_FROM_DSN_BUF(why);
   1093 	for (n = 0; n < request->rcpt_list.len; n++) {
   1094 	    rcpt = request->rcpt_list.info + n;
   1095 	    /* XXX Maybe encapsulate this with ndr_append(). */
   1096 	    status = (STR(why->status)[0] != '4' ?
   1097 		      bounce_append : defer_append)
   1098 		(DEL_REQ_TRACE_FLAGS(request->flags),
   1099 		 request->queue_id,
   1100 		 &request->msg_stats, rcpt,
   1101 		 service, &why->dsn);
   1102 	    if (status == 0)
   1103 		deliver_completed(request->fp, rcpt->offset);
   1104 	    result |= status;
   1105 	}
   1106 	break;
   1107     case PIPE_STAT_CORRUPT:
   1108 	/* XXX DSN should we send something? */
   1109 	result |= DEL_STAT_DEFER;
   1110 	break;
   1111     default:
   1112 	msg_panic("eval_command_status: bad status %d", command_status);
   1113 	/* NOTREACHED */
   1114     }
   1115 
   1116     return (result);
   1117 }
   1118 
   1119 /* deliver_message - deliver message with extreme prejudice */
   1120 
   1121 static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
   1122 {
   1123     const char *myname = "deliver_message";
   1124     static PIPE_PARAMS conf;
   1125     static PIPE_ATTR attr;
   1126     RECIPIENT_LIST *rcpt_list = &request->rcpt_list;
   1127     DSN_BUF *why = dsb_create();
   1128     VSTRING *buf;
   1129     ARGV   *expanded_argv = 0;
   1130     int     deliver_status;
   1131     int     command_status;
   1132     ARGV   *export_env;
   1133     const char *sender;
   1134 
   1135 #define DELIVER_MSG_CLEANUP() { \
   1136 	dsb_free(why); \
   1137 	if (expanded_argv) argv_free(expanded_argv); \
   1138     }
   1139 
   1140     if (msg_verbose)
   1141 	msg_info("%s: from <%s>", myname, request->sender);
   1142 
   1143     /*
   1144      * Sanity checks. The get_service_params() and get_service_attr()
   1145      * routines also do some sanity checks. Look up service attributes and
   1146      * config information only once. This is safe since the information comes
   1147      * from a trusted source, not from the delivery request.
   1148      */
   1149     if (request->nexthop[0] == 0)
   1150 	msg_fatal("empty nexthop hostname");
   1151     if (rcpt_list->len <= 0)
   1152 	msg_fatal("recipient count: %d", rcpt_list->len);
   1153     if (attr.command == 0) {
   1154 	get_service_params(&conf, service);
   1155 	get_service_attr(&attr, argv);
   1156     }
   1157 
   1158     /*
   1159      * The D flag cannot be specified for multi-recipient deliveries.
   1160      */
   1161     if ((attr.flags & MAIL_COPY_DELIVERED) && (rcpt_list->len > 1)) {
   1162 	dsb_simple(why, "4.3.5", "mail system configuration error");
   1163 	deliver_status = eval_command_status(PIPE_STAT_DEFER, service,
   1164 					     request, &attr, why);
   1165 	msg_warn("pipe flag `D' requires %s_destination_recipient_limit = 1",
   1166 		 service);
   1167 	DELIVER_MSG_CLEANUP();
   1168 	return (deliver_status);
   1169     }
   1170 
   1171     /*
   1172      * The O flag cannot be specified for multi-recipient deliveries.
   1173      */
   1174     if ((attr.flags & MAIL_COPY_ORIG_RCPT) && (rcpt_list->len > 1)) {
   1175 	dsb_simple(why, "4.3.5", "mail system configuration error");
   1176 	deliver_status = eval_command_status(PIPE_STAT_DEFER, service,
   1177 					     request, &attr, why);
   1178 	msg_warn("pipe flag `O' requires %s_destination_recipient_limit = 1",
   1179 		 service);
   1180 	DELIVER_MSG_CLEANUP();
   1181 	return (deliver_status);
   1182     }
   1183 
   1184     /*
   1185      * Check that this agent accepts messages this large.
   1186      */
   1187     if (attr.size_limit != 0 && request->data_size > attr.size_limit) {
   1188 	if (msg_verbose)
   1189 	    msg_info("%s: too big: size_limit = %ld, request->data_size = %ld",
   1190 		     myname, (long) attr.size_limit, request->data_size);
   1191 	dsb_simple(why, "5.2.3", "message too large");
   1192 	deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service,
   1193 					     request, &attr, why);
   1194 	DELIVER_MSG_CLEANUP();
   1195 	return (deliver_status);
   1196     }
   1197 
   1198     /*
   1199      * Don't deliver a trace-only request.
   1200      */
   1201     if (DEL_REQ_TRACE_ONLY(request->flags)) {
   1202 	RECIPIENT *rcpt;
   1203 	int     status;
   1204 	int     n;
   1205 
   1206 	deliver_status = 0;
   1207 	dsb_simple(why, "2.0.0", "delivers to command: %s", attr.command[0]);
   1208 	(void) DSN_FROM_DSN_BUF(why);
   1209 	for (n = 0; n < request->rcpt_list.len; n++) {
   1210 	    rcpt = request->rcpt_list.info + n;
   1211 	    status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
   1212 			  request->queue_id, &request->msg_stats,
   1213 			  rcpt, service, &why->dsn);
   1214 	    if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
   1215 		deliver_completed(request->fp, rcpt->offset);
   1216 	    deliver_status |= status;
   1217 	}
   1218 	DELIVER_MSG_CLEANUP();
   1219 	return (deliver_status);
   1220     }
   1221 
   1222     /*
   1223      * Report mail delivery loops. By definition, this requires
   1224      * single-recipient delivery. Don't silently lose recipients.
   1225      */
   1226     if (attr.flags & MAIL_COPY_DELIVERED) {
   1227 	DELIVERED_HDR_INFO *info;
   1228 	RECIPIENT *rcpt;
   1229 	int     loop_found;
   1230 
   1231 	if (request->rcpt_list.len > 1)
   1232 	    msg_panic("%s: delivered-to enabled with multi-recipient request",
   1233 		      myname);
   1234 	info = delivered_hdr_init(request->fp, request->data_offset,
   1235 				  FOLD_ADDR_ALL);
   1236 	rcpt = request->rcpt_list.info;
   1237 	loop_found = delivered_hdr_find(info, rcpt->address);
   1238 	delivered_hdr_free(info);
   1239 	if (loop_found) {
   1240 	    dsb_simple(why, "5.4.6", "mail forwarding loop for %s",
   1241 		       rcpt->address);
   1242 	    deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service,
   1243 						 request, &attr, why);
   1244 	    DELIVER_MSG_CLEANUP();
   1245 	    return (deliver_status);
   1246 	}
   1247     }
   1248 
   1249     /*
   1250      * Deliver. Set the nexthop and sender variables, and expand the command
   1251      * argument vector. Recipients will be expanded on the fly. XXX Rewrite
   1252      * envelope and header addresses according to transport-specific
   1253      * rewriting rules.
   1254      */
   1255     if (vstream_fseek(request->fp, request->data_offset, SEEK_SET) < 0)
   1256 	msg_fatal("seek queue file %s: %m", VSTREAM_PATH(request->fp));
   1257 
   1258     /*
   1259      * A non-empty null sender replacement is subject to the 'q' flag.
   1260      */
   1261     buf = vstring_alloc(10);
   1262     sender = *request->sender ? request->sender : STR(attr.null_sender);
   1263     if (*sender && (attr.flags & PIPE_OPT_QUOTE_LOCAL)) {
   1264 	quote_822_local(buf, sender);
   1265 	dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, STR(buf));
   1266     } else
   1267 	dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, sender);
   1268     if (attr.flags & PIPE_OPT_FOLD_HOST) {
   1269 	casefold(buf, request->nexthop);
   1270 	dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, STR(buf));
   1271     } else
   1272 	dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, request->nexthop);
   1273     vstring_sprintf(buf, "%ld", (long) request->data_size);
   1274     dict_update(PIPE_DICT_TABLE, PIPE_DICT_SIZE, STR(buf));
   1275     dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_ADDR,
   1276 		request->client_addr);
   1277     dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_HELO,
   1278 		request->client_helo);
   1279     dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_NAME,
   1280 		request->client_name);
   1281     dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_PORT,
   1282 		request->client_port);
   1283     dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_PROTO,
   1284 		request->client_proto);
   1285     dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_METHOD,
   1286 		request->sasl_method);
   1287     dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_USERNAME,
   1288 		request->sasl_username);
   1289     dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_SENDER,
   1290 		request->sasl_sender);
   1291     dict_update(PIPE_DICT_TABLE, PIPE_DICT_QUEUE_ID,
   1292 		request->queue_id);
   1293     dict_update(PIPE_DICT_TABLE, PIPE_DICT_ENVID,
   1294 		request->dsn_envid);
   1295     vstring_free(buf);
   1296 
   1297     if ((expanded_argv = expand_argv(service, attr.command,
   1298 				     rcpt_list, attr.flags)) == 0) {
   1299 	dsb_simple(why, "4.3.5", "mail system configuration error");
   1300 	deliver_status = eval_command_status(PIPE_STAT_DEFER, service,
   1301 					     request, &attr, why);
   1302 	DELIVER_MSG_CLEANUP();
   1303 	return (deliver_status);
   1304     }
   1305     export_env = mail_parm_split(VAR_EXPORT_ENVIRON, var_export_environ);
   1306 
   1307     command_status = pipe_command(request->fp, why,
   1308 				  CA_PIPE_CMD_UID(attr.uid),
   1309 				  CA_PIPE_CMD_GID(attr.gid),
   1310 				  CA_PIPE_CMD_SENDER(sender),
   1311 				  CA_PIPE_CMD_COPY_FLAGS(attr.flags),
   1312 				  CA_PIPE_CMD_ARGV(expanded_argv->argv),
   1313 				  CA_PIPE_CMD_TIME_LIMIT(conf.time_limit),
   1314 				  CA_PIPE_CMD_EOL(STR(attr.eol)),
   1315 				  CA_PIPE_CMD_EXPORT(export_env->argv),
   1316 				  CA_PIPE_CMD_CWD(attr.exec_dir),
   1317 				  CA_PIPE_CMD_CHROOT(attr.chroot_dir),
   1318 			CA_PIPE_CMD_ORIG_RCPT(rcpt_list->info[0].orig_addr),
   1319 			  CA_PIPE_CMD_DELIVERED(rcpt_list->info[0].address),
   1320 				  CA_PIPE_CMD_END);
   1321     argv_free(export_env);
   1322 
   1323     deliver_status = eval_command_status(command_status, service, request,
   1324 					 &attr, why);
   1325 
   1326     /*
   1327      * Clean up.
   1328      */
   1329     DELIVER_MSG_CLEANUP();
   1330 
   1331     return (deliver_status);
   1332 }
   1333 
   1334 /* pipe_service - perform service for client */
   1335 
   1336 static void pipe_service(VSTREAM *client_stream, char *service, char **argv)
   1337 {
   1338     DELIVER_REQUEST *request;
   1339     int     status;
   1340 
   1341     /*
   1342      * This routine runs whenever a client connects to the UNIX-domain socket
   1343      * dedicated to delivery via external command. What we see below is a
   1344      * little protocol to (1) tell the queue manager that we are ready, (2)
   1345      * read a request from the queue manager, and (3) report the completion
   1346      * status of that request. All connection-management stuff is handled by
   1347      * the common code in single_server.c.
   1348      */
   1349     if ((request = deliver_request_read(client_stream)) != 0) {
   1350 	status = deliver_message(request, service, argv);
   1351 	deliver_request_done(client_stream, request, status);
   1352     }
   1353 }
   1354 
   1355 /* pre_accept - see if tables have changed */
   1356 
   1357 static void pre_accept(char *unused_name, char **unused_argv)
   1358 {
   1359     const char *table;
   1360 
   1361     if ((table = dict_changed_name()) != 0) {
   1362 	msg_info("table %s has changed -- restarting", table);
   1363 	exit(0);
   1364     }
   1365 }
   1366 
   1367 /* drop_privileges - drop privileges most of the time */
   1368 
   1369 static void drop_privileges(char *unused_name, char **unused_argv)
   1370 {
   1371     set_eugid(var_owner_uid, var_owner_gid);
   1372 }
   1373 
   1374 /* pre_init - initialize */
   1375 
   1376 static void pre_init(char *unused_name, char **unused_argv)
   1377 {
   1378     flush_init();
   1379 }
   1380 
   1381 MAIL_VERSION_STAMP_DECLARE;
   1382 
   1383 /* main - pass control to the single-threaded skeleton */
   1384 
   1385 int     main(int argc, char **argv)
   1386 {
   1387     static const CONFIG_TIME_TABLE time_table[] = {
   1388 	VAR_COMMAND_MAXTIME, DEF_COMMAND_MAXTIME, &var_command_maxtime, 1, 0,
   1389 	0,
   1390     };
   1391     static const CONFIG_STR_TABLE str_table[] = {
   1392 	VAR_PIPE_DSN_FILTER, DEF_PIPE_DSN_FILTER, &var_pipe_dsn_filter, 0, 0,
   1393 	0,
   1394     };
   1395 
   1396     /*
   1397      * Fingerprint executables and core dumps.
   1398      */
   1399     MAIL_VERSION_STAMP_ALLOCATE;
   1400 
   1401     single_server_main(argc, argv, pipe_service,
   1402 		       CA_MAIL_SERVER_TIME_TABLE(time_table),
   1403 		       CA_MAIL_SERVER_STR_TABLE(str_table),
   1404 		       CA_MAIL_SERVER_PRE_INIT(pre_init),
   1405 		       CA_MAIL_SERVER_POST_INIT(drop_privileges),
   1406 		       CA_MAIL_SERVER_PRE_ACCEPT(pre_accept),
   1407 		       CA_MAIL_SERVER_PRIVILEGED,
   1408 		       CA_MAIL_SERVER_BOUNCE_INIT(VAR_PIPE_DSN_FILTER,
   1409 						  &var_pipe_dsn_filter),
   1410 		       0);
   1411 }
   1412