No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / pipe / pipe.c
blob96643172b6469530fe12bcf02e466f5ddb1cf5d5
1 /* $NetBSD$ */
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.
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.
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.
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
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.
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.
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 rights 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 /* In the command argument vector, the following macros are recognized
195 /* and replaced with corresponding information from the Postfix queue
196 /* manager delivery request.
197 /* .sp
198 /* In addition to the form ${\fIname\fR}, the forms $\fIname\fR and
199 /* $(\fIname\fR) are also recognized. Specify \fB$$\fR where a single
200 /* \fB$\fR is wanted.
201 /* .RS
202 /* .IP \fB${\fBclient_address\fR}\fR
203 /* This macro expands to the remote client network address.
204 /* .sp
205 /* This feature is available as of Postfix 2.2.
206 /* .IP \fB${\fBclient_helo\fR}\fR
207 /* This macro expands to the remote client HELO command parameter.
208 /* .sp
209 /* This feature is available as of Postfix 2.2.
210 /* .IP \fB${\fBclient_hostname\fR}\fR
211 /* This macro expands to the remote client hostname.
212 /* .sp
213 /* This feature is available as of Postfix 2.2.
214 /* .IP \fB${\fBclient_port\fR}\fR
215 /* This macro expands to the remote client TCP port number.
216 /* .sp
217 /* This feature is available as of Postfix 2.5.
218 /* .IP \fB${\fBclient_protocol\fR}\fR
219 /* This macro expands to the remote client protocol.
220 /* .sp
221 /* This feature is available as of Postfix 2.2.
222 /* .IP \fB${\fBdomain\fR}\fR
223 /* This macro expands to the domain portion of the recipient
224 /* address. For example, with an address \fIuser+foo@domain\fR
225 /* the domain is \fIdomain\fR.
226 /* .sp
227 /* This information is modified by the \fBh\fR flag for case folding.
228 /* .sp
229 /* This feature is available as of Postfix 2.5.
230 /* .IP \fB${\fBextension\fR}\fR
231 /* This macro expands to the extension part of a recipient address.
232 /* For example, with an address \fIuser+foo@domain\fR the extension is
233 /* \fIfoo\fR.
234 /* .sp
235 /* A command-line argument that contains \fB${\fBextension\fR}\fR expands
236 /* into as many command-line arguments as there are recipients.
237 /* .sp
238 /* This information is modified by the \fBu\fR flag for case folding.
239 /* .IP \fB${\fBmailbox\fR}\fR
240 /* This macro expands to the complete local part of a recipient address.
241 /* For example, with an address \fIuser+foo@domain\fR the mailbox is
242 /* \fIuser+foo\fR.
243 /* .sp
244 /* A command-line argument that contains \fB${\fBmailbox\fR}\fR
245 /* expands to as many command-line arguments as there are recipients.
246 /* .sp
247 /* This information is modified by the \fBu\fR flag for case folding.
248 /* .IP \fB${\fBnexthop\fR}\fR
249 /* This macro expands to the next-hop hostname.
250 /* .sp
251 /* This information is modified by the \fBh\fR flag for case folding.
252 /* .IP \fB${\fBoriginal_recipient\fR}\fR
253 /* This macro expands to the complete recipient address before any
254 /* address rewriting or aliasing.
255 /* .sp
256 /* A command-line argument that contains
257 /* \fB${\fBoriginal_recipient\fR}\fR expands to as many
258 /* command-line arguments as there are recipients.
259 /* .sp
260 /* This information is modified by the \fBhqu\fR flags for quoting
261 /* and case folding.
262 /* .sp
263 /* This feature is available as of Postfix 2.5.
264 /* .IP \fB${\fBrecipient\fR}\fR
265 /* This macro expands to the complete recipient address.
266 /* .sp
267 /* A command-line argument that contains \fB${\fBrecipient\fR}\fR
268 /* expands to as many command-line arguments as there are recipients.
269 /* .sp
270 /* This information is modified by the \fBhqu\fR flags for quoting
271 /* and case folding.
272 /* .IP \fB${\fBsasl_method\fR}\fR
273 /* This macro expands to the name of the SASL authentication
274 /* mechanism in the AUTH command when the Postfix SMTP server
275 /* received the message.
276 /* .sp
277 /* This feature is available as of Postfix 2.2.
278 /* .IP \fB${\fBsasl_sender\fR}\fR
279 /* This macro expands to the SASL sender name (i.e. the original
280 /* submitter as per RFC 4954) in the MAIL FROM command when
281 /* the Postfix SMTP server received the message.
282 /* .sp
283 /* This feature is available as of Postfix 2.2.
284 /* .IP \fB${\fBsasl_username\fR}\fR
285 /* This macro expands to the SASL user name in the AUTH command
286 /* when the Postfix SMTP server received the message.
287 /* .sp
288 /* This feature is available as of Postfix 2.2.
289 /* .IP \fB${\fBsender\fR}\fR
290 /* This macro expands to the envelope sender address. By default,
291 /* the null sender address expands to MAILER-DAEMON; this can
292 /* be changed with the \fBnull_sender\fR attribute, as described
293 /* above.
294 /* .sp
295 /* This information is modified by the \fBq\fR flag for quoting.
296 /* .IP \fB${\fBsize\fR}\fR
297 /* This macro expands to Postfix's idea of the message size, which
298 /* is an approximation of the size of the message as delivered.
299 /* .IP \fB${\fBuser\fR}\fR
300 /* This macro expands to the username part of a recipient address.
301 /* For example, with an address \fIuser+foo@domain\fR the username
302 /* part is \fIuser\fR.
303 /* .sp
304 /* A command-line argument that contains \fB${\fBuser\fR}\fR expands
305 /* into as many command-line arguments as there are recipients.
306 /* .sp
307 /* This information is modified by the \fBu\fR flag for case folding.
308 /* .RE
309 /* STANDARDS
310 /* RFC 3463 (Enhanced status codes)
311 /* DIAGNOSTICS
312 /* Command exit status codes are expected to
313 /* follow the conventions defined in <\fBsysexits.h\fR>.
314 /* Exit status 0 means normal successful completion.
316 /* Postfix version 2.3 and later support RFC 3463-style enhanced
317 /* status codes. If a command terminates with a non-zero exit
318 /* status, and the command output begins with an enhanced
319 /* status code, this status code takes precedence over the
320 /* non-zero exit status.
322 /* Problems and transactions are logged to \fBsyslogd\fR(8).
323 /* Corrupted message files are marked so that the queue manager
324 /* can move them to the \fBcorrupt\fR queue for further inspection.
325 /* SECURITY
326 /* .fi
327 /* .ad
328 /* This program needs a dual personality 1) to access the private
329 /* Postfix queue and IPC mechanisms, and 2) to execute external
330 /* commands as the specified user. It is therefore security sensitive.
331 /* CONFIGURATION PARAMETERS
332 /* .ad
333 /* .fi
334 /* Changes to \fBmain.cf\fR are picked up automatically as \fBpipe\fR(8)
335 /* processes run for only a limited amount of time. Use the command
336 /* "\fBpostfix reload\fR" to speed up a change.
338 /* The text below provides only a parameter summary. See
339 /* \fBpostconf\fR(5) for more details including examples.
340 /* RESOURCE AND RATE CONTROLS
341 /* .ad
342 /* .fi
343 /* In the text below, \fItransport\fR is the first field in a
344 /* \fBmaster.cf\fR entry.
345 /* .IP "\fItransport\fB_destination_concurrency_limit ($default_destination_concurrency_limit)\fR"
346 /* Limit the number of parallel deliveries to the same destination,
347 /* for delivery via the named \fItransport\fR.
348 /* The limit is enforced by the Postfix queue manager.
349 /* .IP "\fItransport\fB_destination_recipient_limit ($default_destination_recipient_limit)\fR"
350 /* Limit the number of recipients per message delivery, for delivery
351 /* via the named \fItransport\fR.
352 /* The limit is enforced by the Postfix queue manager.
353 /* .IP "\fItransport\fB_time_limit ($command_time_limit)\fR"
354 /* Limit the time for delivery to external command, for delivery via
355 /* the named \fItransport\fR.
356 /* The limit is enforced by the pipe delivery agent.
358 /* Postfix 2.4 and later support a suffix that specifies the
359 /* time unit: s (seconds), m (minutes), h (hours), d (days),
360 /* w (weeks). The default time unit is seconds.
361 /* MISCELLANEOUS CONTROLS
362 /* .ad
363 /* .fi
364 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
365 /* The default location of the Postfix main.cf and master.cf
366 /* configuration files.
367 /* .IP "\fBdaemon_timeout (18000s)\fR"
368 /* How much time a Postfix daemon process may take to handle a
369 /* request before it is terminated by a built-in watchdog timer.
370 /* .IP "\fBdelay_logging_resolution_limit (2)\fR"
371 /* The maximal number of digits after the decimal point when logging
372 /* sub-second delay values.
373 /* .IP "\fBexport_environment (see 'postconf -d' output)\fR"
374 /* The list of environment variables that a Postfix process will export
375 /* to non-Postfix processes.
376 /* .IP "\fBipc_timeout (3600s)\fR"
377 /* The time limit for sending or receiving information over an internal
378 /* communication channel.
379 /* .IP "\fBmail_owner (postfix)\fR"
380 /* The UNIX system account that owns the Postfix queue and most Postfix
381 /* daemon processes.
382 /* .IP "\fBmax_idle (100s)\fR"
383 /* The maximum amount of time that an idle Postfix daemon process waits
384 /* for an incoming connection before terminating voluntarily.
385 /* .IP "\fBmax_use (100)\fR"
386 /* The maximal number of incoming connections that a Postfix daemon
387 /* process will service before terminating voluntarily.
388 /* .IP "\fBprocess_id (read-only)\fR"
389 /* The process ID of a Postfix command or daemon process.
390 /* .IP "\fBprocess_name (read-only)\fR"
391 /* The process name of a Postfix command or daemon process.
392 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
393 /* The location of the Postfix top-level queue directory.
394 /* .IP "\fBrecipient_delimiter (empty)\fR"
395 /* The separator between user names and address extensions (user+foo).
396 /* .IP "\fBsyslog_facility (mail)\fR"
397 /* The syslog facility of Postfix logging.
398 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
399 /* The mail system name that is prepended to the process name in syslog
400 /* records, so that "smtpd" becomes, for example, "postfix/smtpd".
401 /* SEE ALSO
402 /* qmgr(8), queue manager
403 /* bounce(8), delivery status reports
404 /* postconf(5), configuration parameters
405 /* master(5), generic daemon options
406 /* master(8), process manager
407 /* syslogd(8), system logging
408 /* LICENSE
409 /* .ad
410 /* .fi
411 /* The Secure Mailer license must be distributed with this software.
412 /* AUTHOR(S)
413 /* Wietse Venema
414 /* IBM T.J. Watson Research
415 /* P.O. Box 704
416 /* Yorktown Heights, NY 10598, USA
417 /*--*/
419 /* System library. */
421 #include <sys_defs.h>
422 #include <unistd.h>
423 #include <stdlib.h>
424 #include <string.h>
425 #include <pwd.h>
426 #include <grp.h>
427 #include <fcntl.h>
428 #include <ctype.h>
430 #ifdef STRCASECMP_IN_STRINGS_H
431 #include <strings.h>
432 #endif
434 /* Utility library. */
436 #include <msg.h>
437 #include <vstream.h>
438 #include <vstring.h>
439 #include <argv.h>
440 #include <htable.h>
441 #include <dict.h>
442 #include <iostuff.h>
443 #include <mymalloc.h>
444 #include <mac_parse.h>
445 #include <set_eugid.h>
446 #include <split_at.h>
447 #include <stringops.h>
449 /* Global library. */
451 #include <recipient_list.h>
452 #include <deliver_request.h>
453 #include <mail_params.h>
454 #include <mail_version.h>
455 #include <mail_conf.h>
456 #include <bounce.h>
457 #include <defer.h>
458 #include <deliver_completed.h>
459 #include <sent.h>
460 #include <pipe_command.h>
461 #include <mail_copy.h>
462 #include <mail_addr.h>
463 #include <canon_addr.h>
464 #include <split_addr.h>
465 #include <off_cvt.h>
466 #include <quote_822_local.h>
467 #include <flush_clnt.h>
468 #include <dsn_util.h>
469 #include <dsn_buf.h>
470 #include <sys_exits.h>
471 #include <delivered_hdr.h>
472 #include <fold_addr.h>
474 /* Single server skeleton. */
476 #include <mail_server.h>
478 /* Application-specific. */
481 * The mini symbol table name and keys used for expanding macros in
482 * command-line arguments.
484 * XXX Update the parse_callback() routine when something gets added here,
485 * even when the macro is not recipient dependent.
487 #define PIPE_DICT_TABLE "pipe_command" /* table name */
488 #define PIPE_DICT_NEXTHOP "nexthop" /* key */
489 #define PIPE_DICT_RCPT "recipient" /* key */
490 #define PIPE_DICT_ORIG_RCPT "original_recipient" /* key */
491 #define PIPE_DICT_SENDER "sender"/* key */
492 #define PIPE_DICT_USER "user" /* key */
493 #define PIPE_DICT_EXTENSION "extension" /* key */
494 #define PIPE_DICT_MAILBOX "mailbox" /* key */
495 #define PIPE_DICT_DOMAIN "domain"/* key */
496 #define PIPE_DICT_SIZE "size" /* key */
497 #define PIPE_DICT_CLIENT_ADDR "client_address" /* key */
498 #define PIPE_DICT_CLIENT_NAME "client_hostname" /* key */
499 #define PIPE_DICT_CLIENT_PORT "client_port" /* key */
500 #define PIPE_DICT_CLIENT_PROTO "client_protocol" /* key */
501 #define PIPE_DICT_CLIENT_HELO "client_helo" /* key */
502 #define PIPE_DICT_SASL_METHOD "sasl_method" /* key */
503 #define PIPE_DICT_SASL_USERNAME "sasl_username" /* key */
504 #define PIPE_DICT_SASL_SENDER "sasl_sender" /* key */
507 * Flags used to pass back the type of special parameter found by
508 * parse_callback.
510 #define PIPE_FLAG_RCPT (1<<0)
511 #define PIPE_FLAG_USER (1<<1)
512 #define PIPE_FLAG_EXTENSION (1<<2)
513 #define PIPE_FLAG_MAILBOX (1<<3)
514 #define PIPE_FLAG_DOMAIN (1<<4)
515 #define PIPE_FLAG_ORIG_RCPT (1<<5)
518 * Additional flags. These are colocated with mail_copy() flags. Allow some
519 * space for extension of the mail_copy() interface.
521 #define PIPE_OPT_FOLD_BASE (16)
522 #define PIPE_OPT_FOLD_USER (FOLD_ADDR_USER << PIPE_OPT_FOLD_BASE)
523 #define PIPE_OPT_FOLD_HOST (FOLD_ADDR_HOST << PIPE_OPT_FOLD_BASE)
524 #define PIPE_OPT_QUOTE_LOCAL (1 << (PIPE_OPT_FOLD_BASE + 2))
525 #define PIPE_OPT_FINAL_DELIVERY (1 << (PIPE_OPT_FOLD_BASE + 3))
527 #define PIPE_OPT_FOLD_ALL (FOLD_ADDR_ALL << PIPE_OPT_FOLD_BASE)
528 #define PIPE_OPT_FOLD_FLAGS(f) \
529 (((f) & PIPE_OPT_FOLD_ALL) >> PIPE_OPT_FOLD_BASE)
532 * Tunable parameters. Values are taken from the config file, after
533 * prepending the service name to _name, and so on.
535 int var_command_maxtime; /* system-wide */
538 * For convenience. Instead of passing around lists of parameters, bundle
539 * them up in convenient structures.
543 * Structure for service-specific configuration parameters.
545 typedef struct {
546 int time_limit; /* per-service time limit */
547 } PIPE_PARAMS;
550 * Structure for command-line parameters.
552 typedef struct {
553 char **command; /* argument vector */
554 uid_t uid; /* command privileges */
555 gid_t gid; /* command privileges */
556 int flags; /* mail_copy() flags */
557 char *exec_dir; /* working directory */
558 char *chroot_dir; /* chroot directory */
559 VSTRING *eol; /* output record delimiter */
560 VSTRING *null_sender; /* null sender expansion */
561 off_t size_limit; /* max size in bytes we will accept */
562 } PIPE_ATTR;
565 * Structure for command-line parameter macro expansion.
567 typedef struct {
568 const char *service; /* for warnings */
569 int expand_flag; /* callback result */
570 } PIPE_STATE;
573 * Silly little macros.
575 #define STR vstring_str
577 /* parse_callback - callback for mac_parse() */
579 static int parse_callback(int type, VSTRING *buf, char *context)
581 PIPE_STATE *state = (PIPE_STATE *) context;
582 struct cmd_flags {
583 const char *name;
584 int flags;
586 static struct cmd_flags cmd_flags[] = {
587 PIPE_DICT_NEXTHOP, 0,
588 PIPE_DICT_RCPT, PIPE_FLAG_RCPT,
589 PIPE_DICT_ORIG_RCPT, PIPE_FLAG_ORIG_RCPT,
590 PIPE_DICT_SENDER, 0,
591 PIPE_DICT_USER, PIPE_FLAG_USER,
592 PIPE_DICT_EXTENSION, PIPE_FLAG_EXTENSION,
593 PIPE_DICT_MAILBOX, PIPE_FLAG_MAILBOX,
594 PIPE_DICT_DOMAIN, PIPE_FLAG_DOMAIN,
595 PIPE_DICT_SIZE, 0,
596 PIPE_DICT_CLIENT_ADDR, 0,
597 PIPE_DICT_CLIENT_NAME, 0,
598 PIPE_DICT_CLIENT_PORT, 0,
599 PIPE_DICT_CLIENT_PROTO, 0,
600 PIPE_DICT_CLIENT_HELO, 0,
601 PIPE_DICT_SASL_METHOD, 0,
602 PIPE_DICT_SASL_USERNAME, 0,
603 PIPE_DICT_SASL_SENDER, 0,
604 0, 0,
606 struct cmd_flags *p;
609 * See if this command-line argument references a special macro.
611 if (type == MAC_PARSE_VARNAME) {
612 for (p = cmd_flags; /* see below */ ; p++) {
613 if (p->name == 0) {
614 msg_warn("file %s/%s: service %s: unknown macro name: \"%s\"",
615 var_config_dir, MASTER_CONF_FILE,
616 state->service, vstring_str(buf));
617 return (MAC_PARSE_ERROR);
618 } else if (strcmp(vstring_str(buf), p->name) == 0) {
619 state->expand_flag |= p->flags;
620 return (0);
624 return (0);
627 /* morph_recipient - morph a recipient address */
629 static void morph_recipient(VSTRING *buf, const char *address, int flags)
633 * Quote the recipient address as appropriate.
635 if (flags & PIPE_OPT_QUOTE_LOCAL)
636 quote_822_local(buf, address);
637 else
638 vstring_strcpy(buf, address);
641 * Fold the recipient address as appropriate.
643 if (flags & PIPE_OPT_FOLD_ALL)
644 fold_addr(STR(buf), PIPE_OPT_FOLD_FLAGS(flags));
647 /* expand_argv - expand macros in the argument vector */
649 static ARGV *expand_argv(const char *service, char **argv,
650 RECIPIENT_LIST *rcpt_list, int flags)
652 VSTRING *buf = vstring_alloc(100);
653 ARGV *result;
654 char **cpp;
655 PIPE_STATE state;
656 int i;
657 char *ext;
658 char *dom;
661 * This appears to be simple operation (replace $name by its expansion).
662 * However, it becomes complex because a command-line argument that
663 * references $recipient must expand to as many command-line arguments as
664 * there are recipients (that's wat programs called by sendmail expect).
665 * So we parse each command-line argument, and depending on what we find,
666 * we either expand the argument just once, or we expand it once for each
667 * recipient. In either case we end up parsing the command-line argument
668 * twice. The amount of CPU time wasted will be negligible.
670 * Note: we can't use recursive macro expansion here, because recursion
671 * would screw up mail addresses that contain $ characters.
673 #define NO 0
674 #define EARLY_RETURN(x) { argv_free(result); vstring_free(buf); return (x); }
676 result = argv_alloc(1);
677 for (cpp = argv; *cpp; cpp++) {
678 state.service = service;
679 state.expand_flag = 0;
680 if (mac_parse(*cpp, parse_callback, (char *) &state) & MAC_PARSE_ERROR)
681 EARLY_RETURN(0);
682 if (state.expand_flag == 0) { /* no $recipient etc. */
683 argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END);
684 } else { /* contains $recipient etc. */
685 for (i = 0; i < rcpt_list->len; i++) {
688 * This argument contains $recipient.
690 if (state.expand_flag & PIPE_FLAG_RCPT) {
691 morph_recipient(buf, rcpt_list->info[i].address, flags);
692 dict_update(PIPE_DICT_TABLE, PIPE_DICT_RCPT, STR(buf));
696 * This argument contains $original_recipient.
698 if (state.expand_flag & PIPE_FLAG_ORIG_RCPT) {
699 morph_recipient(buf, rcpt_list->info[i].orig_addr, flags);
700 dict_update(PIPE_DICT_TABLE, PIPE_DICT_ORIG_RCPT, STR(buf));
704 * This argument contains $user. Extract the plain user name.
705 * Either anything to the left of the extension delimiter or,
706 * in absence of the latter, anything to the left of the
707 * rightmost @.
709 * Beware: if the user name is blank (e.g. +user@host), the
710 * argument is suppressed. This is necessary to allow for
711 * cyrus bulletin-board (global mailbox) delivery. XXX But,
712 * skipping empty user parts will also prevent other
713 * expansions of this specific command-line argument.
715 if (state.expand_flag & PIPE_FLAG_USER) {
716 morph_recipient(buf, rcpt_list->info[i].address,
717 flags & PIPE_OPT_FOLD_ALL);
718 if (split_at_right(STR(buf), '@') == 0)
719 msg_warn("no @ in recipient address: %s",
720 rcpt_list->info[i].address);
721 if (*var_rcpt_delim)
722 split_addr(STR(buf), *var_rcpt_delim);
723 if (*STR(buf) == 0)
724 continue;
725 dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf));
729 * This argument contains $extension. Extract the recipient
730 * extension: anything between the leftmost extension
731 * delimiter and the rightmost @. The extension may be blank.
733 if (state.expand_flag & PIPE_FLAG_EXTENSION) {
734 morph_recipient(buf, rcpt_list->info[i].address,
735 flags & PIPE_OPT_FOLD_ALL);
736 if (split_at_right(STR(buf), '@') == 0)
737 msg_warn("no @ in recipient address: %s",
738 rcpt_list->info[i].address);
739 if (*var_rcpt_delim == 0
740 || (ext = split_addr(STR(buf), *var_rcpt_delim)) == 0)
741 ext = ""; /* insert null arg */
742 dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext);
746 * This argument contains $mailbox. Extract the mailbox name:
747 * anything to the left of the rightmost @.
749 if (state.expand_flag & PIPE_FLAG_MAILBOX) {
750 morph_recipient(buf, rcpt_list->info[i].address,
751 flags & PIPE_OPT_FOLD_ALL);
752 if (split_at_right(STR(buf), '@') == 0)
753 msg_warn("no @ in recipient address: %s",
754 rcpt_list->info[i].address);
755 dict_update(PIPE_DICT_TABLE, PIPE_DICT_MAILBOX, STR(buf));
759 * This argument contains $domain. Extract the domain name:
760 * anything to the right of the rightmost @.
762 if (state.expand_flag & PIPE_FLAG_DOMAIN) {
763 morph_recipient(buf, rcpt_list->info[i].address,
764 flags & PIPE_OPT_FOLD_ALL);
765 dom = split_at_right(STR(buf), '@');
766 if (dom == 0) {
767 msg_warn("no @ in recipient address: %s",
768 rcpt_list->info[i].address);
769 dom = ""; /* insert null arg */
771 dict_update(PIPE_DICT_TABLE, PIPE_DICT_DOMAIN, dom);
775 * Done.
777 argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END);
781 argv_terminate(result);
782 vstring_free(buf);
783 return (result);
786 /* get_service_params - get service-name dependent config information */
788 static void get_service_params(PIPE_PARAMS *config, char *service)
790 const char *myname = "get_service_params";
793 * Figure out the command time limit for this transport.
795 config->time_limit =
796 get_mail_conf_time2(service, _MAXTIME, var_command_maxtime, 's', 1, 0);
799 * Give the poor tester a clue of what is going on.
801 if (msg_verbose)
802 msg_info("%s: time_limit %d", myname, config->time_limit);
805 /* get_service_attr - get command-line attributes */
807 static void get_service_attr(PIPE_ATTR *attr, char **argv)
809 const char *myname = "get_service_attr";
810 struct passwd *pwd;
811 struct group *grp;
812 char *user; /* user name */
813 char *group; /* group name */
814 char *size; /* max message size */
815 char *cp;
818 * Initialize.
820 user = 0;
821 group = 0;
822 attr->command = 0;
823 attr->flags = 0;
824 attr->exec_dir = 0;
825 attr->chroot_dir = 0;
826 attr->eol = vstring_strcpy(vstring_alloc(1), "\n");
827 attr->null_sender = vstring_strcpy(vstring_alloc(1), MAIL_ADDR_MAIL_DAEMON);
828 attr->size_limit = 0;
831 * Iterate over the command-line attribute list.
833 for ( /* void */ ; *argv != 0; argv++) {
836 * flags=stuff
838 if (strncasecmp("flags=", *argv, sizeof("flags=") - 1) == 0) {
839 for (cp = *argv + sizeof("flags=") - 1; *cp; cp++) {
840 switch (*cp) {
841 case 'B':
842 attr->flags |= MAIL_COPY_BLANK;
843 break;
844 case 'D':
845 attr->flags |= MAIL_COPY_DELIVERED;
846 break;
847 case 'F':
848 attr->flags |= MAIL_COPY_FROM;
849 break;
850 case 'O':
851 attr->flags |= MAIL_COPY_ORIG_RCPT;
852 break;
853 case 'R':
854 attr->flags |= MAIL_COPY_RETURN_PATH;
855 break;
856 case 'X':
857 attr->flags |= PIPE_OPT_FINAL_DELIVERY;
858 break;
859 case '.':
860 attr->flags |= MAIL_COPY_DOT;
861 break;
862 case '>':
863 attr->flags |= MAIL_COPY_QUOTE;
864 break;
865 case 'h':
866 attr->flags |= PIPE_OPT_FOLD_HOST;
867 break;
868 case 'q':
869 attr->flags |= PIPE_OPT_QUOTE_LOCAL;
870 break;
871 case 'u':
872 attr->flags |= PIPE_OPT_FOLD_USER;
873 break;
874 default:
875 msg_fatal("unknown flag: %c (ignored)", *cp);
876 break;
882 * user=username[:groupname]
884 else if (strncasecmp("user=", *argv, sizeof("user=") - 1) == 0) {
885 user = *argv + sizeof("user=") - 1;
886 if ((group = split_at(user, ':')) != 0) /* XXX clobbers argv */
887 if (*group == 0)
888 group = 0;
889 if ((pwd = getpwnam(user)) == 0)
890 msg_fatal("%s: unknown username: %s", myname, user);
891 attr->uid = pwd->pw_uid;
892 if (group != 0) {
893 if ((grp = getgrnam(group)) == 0)
894 msg_fatal("%s: unknown group: %s", myname, group);
895 attr->gid = grp->gr_gid;
896 } else {
897 attr->gid = pwd->pw_gid;
902 * directory=string
904 else if (strncasecmp("directory=", *argv, sizeof("directory=") - 1) == 0) {
905 attr->exec_dir = mystrdup(*argv + sizeof("directory=") - 1);
909 * chroot=string
911 else if (strncasecmp("chroot=", *argv, sizeof("chroot=") - 1) == 0) {
912 attr->chroot_dir = mystrdup(*argv + sizeof("chroot=") - 1);
916 * eol=string
918 else if (strncasecmp("eol=", *argv, sizeof("eol=") - 1) == 0) {
919 unescape(attr->eol, *argv + sizeof("eol=") - 1);
923 * null_sender=string
925 else if (strncasecmp("null_sender=", *argv, sizeof("null_sender=") - 1) == 0) {
926 vstring_strcpy(attr->null_sender, *argv + sizeof("null_sender=") - 1);
930 * size=max_message_size (in bytes)
932 else if (strncasecmp("size=", *argv, sizeof("size=") - 1) == 0) {
933 size = *argv + sizeof("size=") - 1;
934 if ((attr->size_limit = off_cvt_string(size)) < 0)
935 msg_fatal("%s: bad size= value: %s", myname, size);
939 * argv=command...
941 else if (strncasecmp("argv=", *argv, sizeof("argv=") - 1) == 0) {
942 *argv += sizeof("argv=") - 1; /* XXX clobbers argv */
943 attr->command = argv;
944 break;
948 * Bad.
950 else
951 msg_fatal("unknown attribute name: %s", *argv);
955 * Sanity checks. Verify that every member has an acceptable value.
957 if (user == 0)
958 msg_fatal("missing user= command-line attribute");
959 if (attr->command == 0)
960 msg_fatal("missing argv= command-line attribute");
961 if (attr->uid == 0)
962 msg_fatal("user= command-line attribute specifies root privileges");
963 if (attr->uid == var_owner_uid)
964 msg_fatal("user= command-line attribute specifies mail system owner %s",
965 var_mail_owner);
966 if (attr->gid == 0)
967 msg_fatal("user= command-line attribute specifies privileged group id 0");
968 if (attr->gid == var_owner_gid)
969 msg_fatal("user= command-line attribute specifies mail system owner %s group id %ld",
970 var_mail_owner, (long) attr->gid);
971 if (attr->gid == var_sgid_gid)
972 msg_fatal("user= command-line attribute specifies mail system %s group id %ld",
973 var_sgid_group, (long) attr->gid);
976 * Give the poor tester a clue of what is going on.
978 if (msg_verbose)
979 msg_info("%s: uid %ld, gid %ld, flags %d, size %ld",
980 myname, (long) attr->uid, (long) attr->gid,
981 attr->flags, (long) attr->size_limit);
984 /* eval_command_status - do something with command completion status */
986 static int eval_command_status(int command_status, char *service,
987 DELIVER_REQUEST *request, PIPE_ATTR *attr,
988 DSN_BUF *why)
990 RECIPIENT *rcpt;
991 int status;
992 int result = 0;
993 int n;
996 * Depending on the result, bounce or defer the message, and mark the
997 * recipient as done where appropriate.
999 switch (command_status) {
1000 case PIPE_STAT_OK:
1001 dsb_update(why, "2.0.0", (attr->flags & PIPE_OPT_FINAL_DELIVERY) ?
1002 "delivered" : "relayed", DSB_SKIP_RMTA, DSB_SKIP_REPLY,
1003 "delivered via %s service", service);
1004 (void) DSN_FROM_DSN_BUF(why);
1005 for (n = 0; n < request->rcpt_list.len; n++) {
1006 rcpt = request->rcpt_list.info + n;
1007 status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
1008 request->queue_id, &request->msg_stats, rcpt,
1009 service, &why->dsn);
1010 if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
1011 deliver_completed(request->fp, rcpt->offset);
1012 result |= status;
1014 break;
1015 case PIPE_STAT_BOUNCE:
1016 case PIPE_STAT_DEFER:
1017 (void) DSN_FROM_DSN_BUF(why);
1018 if (STR(why->status)[0] != '4') {
1019 for (n = 0; n < request->rcpt_list.len; n++) {
1020 rcpt = request->rcpt_list.info + n;
1021 status = bounce_append(DEL_REQ_TRACE_FLAGS(request->flags),
1022 request->queue_id,
1023 &request->msg_stats, rcpt,
1024 service, &why->dsn);
1025 if (status == 0)
1026 deliver_completed(request->fp, rcpt->offset);
1027 result |= status;
1029 } else {
1030 for (n = 0; n < request->rcpt_list.len; n++) {
1031 rcpt = request->rcpt_list.info + n;
1032 result |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
1033 request->queue_id,
1034 &request->msg_stats, rcpt,
1035 service, &why->dsn);
1038 break;
1039 case PIPE_STAT_CORRUPT:
1040 /* XXX DSN should we send something? */
1041 result |= DEL_STAT_DEFER;
1042 break;
1043 default:
1044 msg_panic("eval_command_status: bad status %d", command_status);
1045 /* NOTREACHED */
1048 return (result);
1051 /* deliver_message - deliver message with extreme prejudice */
1053 static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
1055 const char *myname = "deliver_message";
1056 static PIPE_PARAMS conf;
1057 static PIPE_ATTR attr;
1058 RECIPIENT_LIST *rcpt_list = &request->rcpt_list;
1059 DSN_BUF *why = dsb_create();
1060 VSTRING *buf;
1061 ARGV *expanded_argv = 0;
1062 int deliver_status;
1063 int command_status;
1064 ARGV *export_env;
1065 const char *sender;
1067 #define DELIVER_MSG_CLEANUP() { \
1068 dsb_free(why); \
1069 if (expanded_argv) argv_free(expanded_argv); \
1072 if (msg_verbose)
1073 msg_info("%s: from <%s>", myname, request->sender);
1076 * Sanity checks. The get_service_params() and get_service_attr()
1077 * routines also do some sanity checks. Look up service attributes and
1078 * config information only once. This is safe since the information comes
1079 * from a trusted source, not from the delivery request.
1081 if (request->nexthop[0] == 0)
1082 msg_fatal("empty nexthop hostname");
1083 if (rcpt_list->len <= 0)
1084 msg_fatal("recipient count: %d", rcpt_list->len);
1085 if (attr.command == 0) {
1086 get_service_params(&conf, service);
1087 get_service_attr(&attr, argv);
1091 * The D flag cannot be specified for multi-recipient deliveries.
1093 if ((attr.flags & MAIL_COPY_DELIVERED) && (rcpt_list->len > 1)) {
1094 dsb_simple(why, "4.3.5", "mail system configuration error");
1095 deliver_status = eval_command_status(PIPE_STAT_DEFER, service,
1096 request, &attr, why);
1097 msg_warn("pipe flag `D' requires %s_destination_recipient_limit = 1",
1098 service);
1099 DELIVER_MSG_CLEANUP();
1100 return (deliver_status);
1104 * The O flag cannot be specified for multi-recipient deliveries.
1106 if ((attr.flags & MAIL_COPY_ORIG_RCPT) && (rcpt_list->len > 1)) {
1107 dsb_simple(why, "4.3.5", "mail system configuration error");
1108 deliver_status = eval_command_status(PIPE_STAT_DEFER, service,
1109 request, &attr, why);
1110 msg_warn("pipe flag `O' requires %s_destination_recipient_limit = 1",
1111 service);
1112 DELIVER_MSG_CLEANUP();
1113 return (deliver_status);
1117 * Check that this agent accepts messages this large.
1119 if (attr.size_limit != 0 && request->data_size > attr.size_limit) {
1120 if (msg_verbose)
1121 msg_info("%s: too big: size_limit = %ld, request->data_size = %ld",
1122 myname, (long) attr.size_limit, request->data_size);
1123 dsb_simple(why, "5.2.3", "message too large");
1124 deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service,
1125 request, &attr, why);
1126 DELIVER_MSG_CLEANUP();
1127 return (deliver_status);
1131 * Don't deliver a trace-only request.
1133 if (DEL_REQ_TRACE_ONLY(request->flags)) {
1134 RECIPIENT *rcpt;
1135 int status;
1136 int n;
1138 deliver_status = 0;
1139 dsb_simple(why, "2.0.0", "delivers to command: %s", attr.command[0]);
1140 (void) DSN_FROM_DSN_BUF(why);
1141 for (n = 0; n < request->rcpt_list.len; n++) {
1142 rcpt = request->rcpt_list.info + n;
1143 status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
1144 request->queue_id, &request->msg_stats,
1145 rcpt, service, &why->dsn);
1146 if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
1147 deliver_completed(request->fp, rcpt->offset);
1148 deliver_status |= status;
1150 DELIVER_MSG_CLEANUP();
1151 return (deliver_status);
1155 * Report mail delivery loops. By definition, this requires
1156 * single-recipient delivery. Don't silently lose recipients.
1158 if (attr.flags & MAIL_COPY_DELIVERED) {
1159 DELIVERED_HDR_INFO *info;
1160 RECIPIENT *rcpt;
1161 int loop_found;
1163 if (request->rcpt_list.len > 1)
1164 msg_panic("%s: delivered-to enabled with multi-recipient request",
1165 myname);
1166 info = delivered_hdr_init(request->fp, request->data_offset,
1167 FOLD_ADDR_ALL);
1168 rcpt = request->rcpt_list.info;
1169 loop_found = delivered_hdr_find(info, rcpt->address);
1170 delivered_hdr_free(info);
1171 if (loop_found) {
1172 dsb_simple(why, "5.4.6", "mail forwarding loop for %s",
1173 rcpt->address);
1174 deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service,
1175 request, &attr, why);
1176 DELIVER_MSG_CLEANUP();
1177 return (deliver_status);
1182 * Deliver. Set the nexthop and sender variables, and expand the command
1183 * argument vector. Recipients will be expanded on the fly. XXX Rewrite
1184 * envelope and header addresses according to transport-specific
1185 * rewriting rules.
1187 if (vstream_fseek(request->fp, request->data_offset, SEEK_SET) < 0)
1188 msg_fatal("seek queue file %s: %m", VSTREAM_PATH(request->fp));
1191 * A non-empty null sender replacement is subject to the 'q' flag.
1193 buf = vstring_alloc(10);
1194 sender = *request->sender ? request->sender : STR(attr.null_sender);
1195 if (*sender && (attr.flags & PIPE_OPT_QUOTE_LOCAL)) {
1196 quote_822_local(buf, sender);
1197 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, STR(buf));
1198 } else
1199 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, sender);
1200 if (attr.flags & PIPE_OPT_FOLD_HOST) {
1201 vstring_strcpy(buf, request->nexthop);
1202 lowercase(STR(buf));
1203 dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, STR(buf));
1204 } else
1205 dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, request->nexthop);
1206 vstring_sprintf(buf, "%ld", (long) request->data_size);
1207 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SIZE, STR(buf));
1208 dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_ADDR,
1209 request->client_addr);
1210 dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_HELO,
1211 request->client_helo);
1212 dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_NAME,
1213 request->client_name);
1214 dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_PORT,
1215 request->client_port);
1216 dict_update(PIPE_DICT_TABLE, PIPE_DICT_CLIENT_PROTO,
1217 request->client_proto);
1218 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_METHOD,
1219 request->sasl_method);
1220 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_USERNAME,
1221 request->sasl_username);
1222 dict_update(PIPE_DICT_TABLE, PIPE_DICT_SASL_SENDER,
1223 request->sasl_sender);
1224 vstring_free(buf);
1226 if ((expanded_argv = expand_argv(service, attr.command,
1227 rcpt_list, attr.flags)) == 0) {
1228 dsb_simple(why, "4.3.5", "mail system configuration error");
1229 deliver_status = eval_command_status(PIPE_STAT_DEFER, service,
1230 request, &attr, why);
1231 DELIVER_MSG_CLEANUP();
1232 return (deliver_status);
1234 export_env = argv_split(var_export_environ, ", \t\r\n");
1236 command_status = pipe_command(request->fp, why,
1237 PIPE_CMD_UID, attr.uid,
1238 PIPE_CMD_GID, attr.gid,
1239 PIPE_CMD_SENDER, sender,
1240 PIPE_CMD_COPY_FLAGS, attr.flags,
1241 PIPE_CMD_ARGV, expanded_argv->argv,
1242 PIPE_CMD_TIME_LIMIT, conf.time_limit,
1243 PIPE_CMD_EOL, STR(attr.eol),
1244 PIPE_CMD_EXPORT, export_env->argv,
1245 PIPE_CMD_CWD, attr.exec_dir,
1246 PIPE_CMD_CHROOT, attr.chroot_dir,
1247 PIPE_CMD_ORIG_RCPT, rcpt_list->info[0].orig_addr,
1248 PIPE_CMD_DELIVERED, rcpt_list->info[0].address,
1249 PIPE_CMD_END);
1250 argv_free(export_env);
1252 deliver_status = eval_command_status(command_status, service, request,
1253 &attr, why);
1256 * Clean up.
1258 DELIVER_MSG_CLEANUP();
1260 return (deliver_status);
1263 /* pipe_service - perform service for client */
1265 static void pipe_service(VSTREAM *client_stream, char *service, char **argv)
1267 DELIVER_REQUEST *request;
1268 int status;
1271 * This routine runs whenever a client connects to the UNIX-domain socket
1272 * dedicated to delivery via external command. What we see below is a
1273 * little protocol to (1) tell the queue manager that we are ready, (2)
1274 * read a request from the queue manager, and (3) report the completion
1275 * status of that request. All connection-management stuff is handled by
1276 * the common code in single_server.c.
1278 if ((request = deliver_request_read(client_stream)) != 0) {
1279 status = deliver_message(request, service, argv);
1280 deliver_request_done(client_stream, request, status);
1284 /* pre_accept - see if tables have changed */
1286 static void pre_accept(char *unused_name, char **unused_argv)
1288 const char *table;
1290 if ((table = dict_changed_name()) != 0) {
1291 msg_info("table %s has changed -- restarting", table);
1292 exit(0);
1296 /* drop_privileges - drop privileges most of the time */
1298 static void drop_privileges(char *unused_name, char **unused_argv)
1300 set_eugid(var_owner_uid, var_owner_gid);
1303 /* pre_init - initialize */
1305 static void pre_init(char *unused_name, char **unused_argv)
1307 flush_init();
1310 MAIL_VERSION_STAMP_DECLARE;
1312 /* main - pass control to the single-threaded skeleton */
1314 int main(int argc, char **argv)
1316 static const CONFIG_TIME_TABLE time_table[] = {
1317 VAR_COMMAND_MAXTIME, DEF_COMMAND_MAXTIME, &var_command_maxtime, 1, 0,
1322 * Fingerprint executables and core dumps.
1324 MAIL_VERSION_STAMP_ALLOCATE;
1326 single_server_main(argc, argv, pipe_service,
1327 MAIL_SERVER_TIME_TABLE, time_table,
1328 MAIL_SERVER_PRE_INIT, pre_init,
1329 MAIL_SERVER_POST_INIT, drop_privileges,
1330 MAIL_SERVER_PRE_ACCEPT, pre_accept,
1331 MAIL_SERVER_PRIVILEGED,