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