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