1 /* $NetBSD: pipe.c,v 1.1.1.3 2011/03/02 19:32:24 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* pipe 8 6 /* SUMMARY 7 /* Postfix delivery to external command 8 /* SYNOPSIS 9 /* \fBpipe\fR [generic Postfix daemon options] command_attributes... 10 /* DESCRIPTION 11 /* The \fBpipe\fR(8) daemon processes requests from the Postfix queue 12 /* manager to deliver messages to external commands. 13 /* This program expects to be run from the \fBmaster\fR(8) process 14 /* manager. 15 /* 16 /* Message attributes such as sender address, recipient address and 17 /* next-hop host name can be specified as command-line macros that are 18 /* expanded before the external command is executed. 19 /* 20 /* The \fBpipe\fR(8) daemon updates queue files and marks recipients 21 /* as finished, or it informs the queue manager that delivery should 22 /* be tried again at a later time. Delivery status reports are sent 23 /* to the \fBbounce\fR(8), \fBdefer\fR(8) or \fBtrace\fR(8) daemon as 24 /* appropriate. 25 /* SINGLE-RECIPIENT DELIVERY 26 /* .ad 27 /* .fi 28 /* Some destinations cannot handle more than one recipient per 29 /* delivery request. Examples are pagers or fax machines. 30 /* In addition, multi-recipient delivery is undesirable when 31 /* prepending a \fBDelivered-to:\fR or \fBX-Original-To:\fR 32 /* message header. 33 /* 34 /* To prevent Postfix from sending multiple recipients per delivery 35 /* request, specify 36 /* .sp 37 /* .nf 38 /* \fItransport\fB_destination_recipient_limit = 1\fR 39 /* .fi 40 /* 41 /* in the Postfix \fBmain.cf\fR file, where \fItransport\fR 42 /* is the name in the first column of the Postfix \fBmaster.cf\fR 43 /* entry for the pipe-based delivery transport. 44 /* COMMAND ATTRIBUTE SYNTAX 45 /* .ad 46 /* .fi 47 /* The external command attributes are given in the \fBmaster.cf\fR 48 /* file at the end of a service definition. The syntax is as follows: 49 /* .IP "\fBchroot=\fIpathname\fR (optional)" 50 /* Change the process root directory and working directory to 51 /* the named directory. This happens before switching to the 52 /* privileges specified with the \fBuser\fR attribute, and 53 /* before executing the optional \fBdirectory=\fIpathname\fR 54 /* directive. Delivery is deferred in case of failure. 55 /* .sp 56 /* This feature is available as of Postfix 2.3. 57 /* .IP "\fBdirectory=\fIpathname\fR (optional)" 58 /* Change to the named directory before executing the external command. 59 /* The directory must be accessible for the user specified with the 60 /* \fBuser\fR attribute (see below). 61 /* The default working directory is \fB$queue_directory\fR. 62 /* Delivery is deferred in case of failure. 63 /* .sp 64 /* This feature is available as of Postfix 2.2. 65 /* .IP "\fBeol=\fIstring\fR (optional, default: \fB\en\fR)" 66 /* The output record delimiter. Typically one would use either 67 /* \fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape 68 /* sequences are recognized: \fB\ea \eb \ef \en \er \et \ev 69 /* \e\fIddd\fR (up to three octal digits) and \fB\e\e\fR. 70 /* .IP "\fBflags=BDFORXhqu.>\fR (optional)" 71 /* Optional message processing flags. By default, a message is 72 /* copied unchanged. 73 /* .RS 74 /* .IP \fBB\fR 75 /* Append a blank line at the end of each message. This is required 76 /* by some mail user agents that recognize "\fBFrom \fR" lines only 77 /* when preceded by a blank line. 78 /* .IP \fBD\fR 79 /* Prepend a "\fBDelivered-To: \fIrecipient\fR" message header with the 80 /* envelope recipient address. Note: for this to work, the 81 /* \fItransport\fB_destination_recipient_limit\fR must be 1 82 /* (see SINGLE-RECIPIENT DELIVERY above for details). 83 /* .sp 84 /* The \fBD\fR flag also enforces loop detection (Postfix 2.5 and later): 85 /* if a message already contains a \fBDelivered-To:\fR header 86 /* with the same recipient address, then the message is 87 /* returned as undeliverable. The address comparison is case 88 /* insensitive. 89 /* .sp 90 /* This feature is available as of Postfix 2.0. 91 /* .IP \fBF\fR 92 /* Prepend a "\fBFrom \fIsender time_stamp\fR" envelope header to 93 /* the message content. 94 /* This is expected by, for example, \fBUUCP\fR software. 95 /* .IP \fBO\fR 96 /* Prepend an "\fBX-Original-To: \fIrecipient\fR" message header 97 /* with the recipient address as given to Postfix. Note: for this to 98 /* work, the \fItransport\fB_destination_recipient_limit\fR must be 1 99 /* (see SINGLE-RECIPIENT DELIVERY above for details). 100 /* .sp 101 /* This feature is available as of Postfix 2.0. 102 /* .IP \fBR\fR 103 /* Prepend a \fBReturn-Path:\fR message header with the envelope sender 104 /* address. 105 /* .IP \fBX\fR 106 /* Indicate that the external command performs final delivery. 107 /* This flag affects the status reported in "success" DSN 108 /* (delivery status notification) messages, and changes it 109 /* from "relayed" into "delivered". 110 /* .sp 111 /* This feature is available as of Postfix 2.5. 112 /* .IP \fBh\fR 113 /* Fold the command-line \fB$original_recipient\fR and 114 /* \fB$recipient\fR address domain part 115 /* (text to the right of the right-most \fB@\fR character) to 116 /* lower case; fold the entire command-line \fB$domain\fR and 117 /* \fB$nexthop\fR host or domain information to lower case. 118 /* This is recommended for delivery via \fBUUCP\fR. 119 /* .IP \fBq\fR 120 /* Quote white space and other special characters in the command-line 121 /* \fB$sender\fR, \fB$original_recipient\fR and \fB$recipient\fR 122 /* address localparts (text to the 123 /* left of the right-most \fB@\fR character), according to an 8-bit 124 /* transparent version of RFC 822. 125 /* This is recommended for delivery via \fBUUCP\fR or \fBBSMTP\fR. 126 /* .sp 127 /* The result is compatible with the address parsing of command-line 128 /* recipients by the Postfix \fBsendmail\fR(1) mail submission command. 129 /* .sp 130 /* The \fBq\fR flag affects only entire addresses, not the partial 131 /* address information from the \fB$user\fR, \fB$extension\fR or 132 /* \fB$mailbox\fR command-line macros. 133 /* .IP \fBu\fR 134 /* Fold the command-line \fB$original_recipient\fR and 135 /* \fB$recipient\fR address localpart (text to 136 /* the left of the right-most \fB@\fR character) to lower case. 137 /* This is recommended for delivery via \fBUUCP\fR. 138 /* .IP \fB.\fR 139 /* Prepend "\fB.\fR" to lines starting with "\fB.\fR". This is needed 140 /* by, for example, \fBBSMTP\fR software. 141 /* .IP \fB>\fR 142 /* Prepend "\fB>\fR" to lines starting with "\fBFrom \fR". This is expected 143 /* by, for example, \fBUUCP\fR software. 144 /* .RE 145 /* .IP "\fBnull_sender\fR=\fIreplacement\fR (default: MAILER-DAEMON)" 146 /* Replace the null sender address (typically used for delivery 147 /* status notifications) with the specified text 148 /* when expanding the \fB$sender\fR command-line macro, and 149 /* when generating a From_ or Return-Path: message header. 150 /* 151 /* If the null sender replacement text is a non-empty string 152 /* then it is affected by the \fBq\fR flag for address quoting 153 /* in command-line arguments. 154 /* 155 /* The null sender replacement text may be empty; this form 156 /* is recommended for content filters that feed mail back into 157 /* Postfix. The empty sender address is not affected by the 158 /* \fBq\fR flag for address quoting in command-line arguments. 159 /* .sp 160 /* Caution: a null sender address is easily mis-parsed by 161 /* naive software. For example, when the \fBpipe\fR(8) daemon 162 /* executes a command such as: 163 /* .sp 164 /* .nf 165 /* \fIWrong\fR: command -f$sender -- $recipient 166 /* .fi 167 /* .IP 168 /* the command will mis-parse the -f option value when the 169 /* sender address is a null string. For correct parsing, 170 /* specify \fB$sender\fR as an argument by itself: 171 /* .sp 172 /* .nf 173 /* \fIRight\fR: command -f $sender -- $recipient 174 /* .fi 175 /* .IP 176 /* This feature is available as of Postfix 2.3. 177 /* .IP "\fBsize\fR=\fIsize_limit\fR (optional)" 178 /* Don't deliver messages that exceed this size limit (in 179 /* bytes); return them to the sender instead. 180 /* .IP "\fBuser\fR=\fIusername\fR (required)" 181 /* .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR" 182 /* Execute the external command with the user ID and group ID of the 183 /* specified \fIusername\fR. The software refuses to execute 184 /* commands with root privileges, or with the privileges of the 185 /* mail system owner. If \fIgroupname\fR is specified, the 186 /* corresponding group ID is used instead of the group ID of 187 /* \fIusername\fR. 188 /* .IP "\fBargv\fR=\fIcommand\fR... (required)" 189 /* The command to be executed. This must be specified as the 190 /* last command attribute. 191 /* The command is executed directly, i.e. without interpretation of 192 /* shell meta characters by a shell command interpreter. 193 /* .sp 194 /* 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. 315 /* 316 /* In the case of a non-zero exit status, a limited amount of 317 /* command output is reported in an delivery status notification. 318 /* When the output begins with a 4.X.X or 5.X.X enhanced status 319 /* code, the status code takes precedence over the non-zero 320 /* exit status (Postfix version 2.3 and later). 321 /* 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. 337 /* 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. 357 /* 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 /*--*/ 418 419 /* System library. */ 420 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> 429 430 #ifdef STRCASECMP_IN_STRINGS_H 431 #include <strings.h> 432 #endif 433 434 /* Utility library. */ 435 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> 448 449 /* Global library. */ 450 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> 473 474 /* Single server skeleton. */ 475 476 #include <mail_server.h> 477 478 /* Application-specific. */ 479 480 /* 481 * The mini symbol table name and keys used for expanding macros in 482 * command-line arguments. 483 * 484 * XXX Update the parse_callback() routine when something gets added here, 485 * even when the macro is not recipient dependent. 486 */ 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 */ 505 506 /* 507 * Flags used to pass back the type of special parameter found by 508 * parse_callback. 509 */ 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) 516 517 /* 518 * Additional flags. These are colocated with mail_copy() flags. Allow some 519 * space for extension of the mail_copy() interface. 520 */ 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)) 526 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) 530 531 /* 532 * Tunable parameters. Values are taken from the config file, after 533 * prepending the service name to _name, and so on. 534 */ 535 int var_command_maxtime; /* You can now leave this here. */ 536 537 /* 538 * For convenience. Instead of passing around lists of parameters, bundle 539 * them up in convenient structures. 540 */ 541 542 /* 543 * Structure for service-specific configuration parameters. 544 */ 545 typedef struct { 546 int time_limit; /* per-service time limit */ 547 } PIPE_PARAMS; 548 549 /* 550 * Structure for command-line parameters. 551 */ 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; 563 564 /* 565 * Structure for command-line parameter macro expansion. 566 */ 567 typedef struct { 568 const char *service; /* for warnings */ 569 int expand_flag; /* callback result */ 570 } PIPE_STATE; 571 572 /* 573 * Silly little macros. 574 */ 575 #define STR vstring_str 576 577 /* parse_callback - callback for mac_parse() */ 578 579 static int parse_callback(int type, VSTRING *buf, char *context) 580 { 581 PIPE_STATE *state = (PIPE_STATE *) context; 582 struct cmd_flags { 583 const char *name; 584 int flags; 585 }; 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, 605 }; 606 struct cmd_flags *p; 607 608 /* 609 * See if this command-line argument references a special macro. 610 */ 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); 621 } 622 } 623 } 624 return (0); 625 } 626 627 /* morph_recipient - morph a recipient address */ 628 629 static void morph_recipient(VSTRING *buf, const char *address, int flags) 630 { 631 632 /* 633 * Quote the recipient address as appropriate. 634 */ 635 if (flags & PIPE_OPT_QUOTE_LOCAL) 636 quote_822_local(buf, address); 637 else 638 vstring_strcpy(buf, address); 639 640 /* 641 * Fold the recipient address as appropriate. 642 */ 643 if (flags & PIPE_OPT_FOLD_ALL) 644 fold_addr(STR(buf), PIPE_OPT_FOLD_FLAGS(flags)); 645 } 646 647 /* expand_argv - expand macros in the argument vector */ 648 649 static ARGV *expand_argv(const char *service, char **argv, 650 RECIPIENT_LIST *rcpt_list, int flags) 651 { 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; 659 660 /* 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. 669 * 670 * Note: we can't use recursive macro expansion here, because recursion 671 * would screw up mail addresses that contain $ characters. 672 */ 673 #define NO 0 674 #define EARLY_RETURN(x) { argv_free(result); vstring_free(buf); return (x); } 675 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++) { 686 687 /* 688 * This argument contains $recipient. 689 */ 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)); 693 } 694 695 /* 696 * This argument contains $original_recipient. 697 */ 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)); 701 } 702 703 /* 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 @. 708 * 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. 714 */ 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)); 726 } 727 728 /* 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. 732 */ 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); 743 } 744 745 /* 746 * This argument contains $mailbox. Extract the mailbox name: 747 * anything to the left of the rightmost @. 748 */ 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)); 756 } 757 758 /* 759 * This argument contains $domain. Extract the domain name: 760 * anything to the right of the rightmost @. 761 */ 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 */ 770 } 771 dict_update(PIPE_DICT_TABLE, PIPE_DICT_DOMAIN, dom); 772 } 773 774 /* 775 * Done. 776 */ 777 argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END); 778 } 779 } 780 } 781 argv_terminate(result); 782 vstring_free(buf); 783 return (result); 784 } 785 786 /* get_service_params - get service-name dependent config information */ 787 788 static void get_service_params(PIPE_PARAMS *config, char *service) 789 { 790 const char *myname = "get_service_params"; 791 792 /* 793 * Figure out the command time limit for this transport. 794 */ 795 config->time_limit = 796 get_mail_conf_time2(service, _MAXTIME, var_command_maxtime, 's', 1, 0); 797 798 /* 799 * Give the poor tester a clue of what is going on. 800 */ 801 if (msg_verbose) 802 msg_info("%s: time_limit %d", myname, config->time_limit); 803 } 804 805 /* get_service_attr - get command-line attributes */ 806 807 static void get_service_attr(PIPE_ATTR *attr, char **argv) 808 { 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; 816 817 /* 818 * Initialize. 819 */ 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; 829 830 /* 831 * Iterate over the command-line attribute list. 832 */ 833 for ( /* void */ ; *argv != 0; argv++) { 834 835 /* 836 * flags=stuff 837 */ 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; 877 } 878 } 879 } 880 881 /* 882 * user=username[:groupname] 883 */ 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; 898 } 899 } 900 901 /* 902 * directory=string 903 */ 904 else if (strncasecmp("directory=", *argv, sizeof("directory=") - 1) == 0) { 905 attr->exec_dir = mystrdup(*argv + sizeof("directory=") - 1); 906 } 907 908 /* 909 * chroot=string 910 */ 911 else if (strncasecmp("chroot=", *argv, sizeof("chroot=") - 1) == 0) { 912 attr->chroot_dir = mystrdup(*argv + sizeof("chroot=") - 1); 913 } 914 915 /* 916 * eol=string 917 */ 918 else if (strncasecmp("eol=", *argv, sizeof("eol=") - 1) == 0) { 919 unescape(attr->eol, *argv + sizeof("eol=") - 1); 920 } 921 922 /* 923 * null_sender=string 924 */ 925 else if (strncasecmp("null_sender=", *argv, sizeof("null_sender=") - 1) == 0) { 926 vstring_strcpy(attr->null_sender, *argv + sizeof("null_sender=") - 1); 927 } 928 929 /* 930 * size=max_message_size (in bytes) 931 */ 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); 936 } 937 938 /* 939 * argv=command... 940 */ 941 else if (strncasecmp("argv=", *argv, sizeof("argv=") - 1) == 0) { 942 *argv += sizeof("argv=") - 1; /* XXX clobbers argv */ 943 attr->command = argv; 944 break; 945 } 946 947 /* 948 * Bad. 949 */ 950 else 951 msg_fatal("unknown attribute name: %s", *argv); 952 } 953 954 /* 955 * Sanity checks. Verify that every member has an acceptable value. 956 */ 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); 974 975 /* 976 * Give the poor tester a clue of what is going on. 977 */ 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); 982 } 983 984 /* eval_command_status - do something with command completion status */ 985 986 static int eval_command_status(int command_status, char *service, 987 DELIVER_REQUEST *request, PIPE_ATTR *attr, 988 DSN_BUF *why) 989 { 990 RECIPIENT *rcpt; 991 int status; 992 int result = 0; 993 int n; 994 995 /* 996 * Depending on the result, bounce or defer the message, and mark the 997 * recipient as done where appropriate. 998 */ 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; 1013 } 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; 1028 } 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); 1036 } 1037 } 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 */ 1046 } 1047 1048 return (result); 1049 } 1050 1051 /* deliver_message - deliver message with extreme prejudice */ 1052 1053 static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv) 1054 { 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; 1066 1067 #define DELIVER_MSG_CLEANUP() { \ 1068 dsb_free(why); \ 1069 if (expanded_argv) argv_free(expanded_argv); \ 1070 } 1071 1072 if (msg_verbose) 1073 msg_info("%s: from <%s>", myname, request->sender); 1074 1075 /* 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. 1080 */ 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); 1088 } 1089 1090 /* 1091 * The D flag cannot be specified for multi-recipient deliveries. 1092 */ 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); 1101 } 1102 1103 /* 1104 * The O flag cannot be specified for multi-recipient deliveries. 1105 */ 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); 1114 } 1115 1116 /* 1117 * Check that this agent accepts messages this large. 1118 */ 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); 1128 } 1129 1130 /* 1131 * Don't deliver a trace-only request. 1132 */ 1133 if (DEL_REQ_TRACE_ONLY(request->flags)) { 1134 RECIPIENT *rcpt; 1135 int status; 1136 int n; 1137 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; 1149 } 1150 DELIVER_MSG_CLEANUP(); 1151 return (deliver_status); 1152 } 1153 1154 /* 1155 * Report mail delivery loops. By definition, this requires 1156 * single-recipient delivery. Don't silently lose recipients. 1157 */ 1158 if (attr.flags & MAIL_COPY_DELIVERED) { 1159 DELIVERED_HDR_INFO *info; 1160 RECIPIENT *rcpt; 1161 int loop_found; 1162 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); 1178 } 1179 } 1180 1181 /* 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. 1186 */ 1187 if (vstream_fseek(request->fp, request->data_offset, SEEK_SET) < 0) 1188 msg_fatal("seek queue file %s: %m", VSTREAM_PATH(request->fp)); 1189 1190 /* 1191 * A non-empty null sender replacement is subject to the 'q' flag. 1192 */ 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); 1225 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); 1233 } 1234 export_env = argv_split(var_export_environ, ", \t\r\n"); 1235 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); 1251 1252 deliver_status = eval_command_status(command_status, service, request, 1253 &attr, why); 1254 1255 /* 1256 * Clean up. 1257 */ 1258 DELIVER_MSG_CLEANUP(); 1259 1260 return (deliver_status); 1261 } 1262 1263 /* pipe_service - perform service for client */ 1264 1265 static void pipe_service(VSTREAM *client_stream, char *service, char **argv) 1266 { 1267 DELIVER_REQUEST *request; 1268 int status; 1269 1270 /* 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. 1277 */ 1278 if ((request = deliver_request_read(client_stream)) != 0) { 1279 status = deliver_message(request, service, argv); 1280 deliver_request_done(client_stream, request, status); 1281 } 1282 } 1283 1284 /* pre_accept - see if tables have changed */ 1285 1286 static void pre_accept(char *unused_name, char **unused_argv) 1287 { 1288 const char *table; 1289 1290 if ((table = dict_changed_name()) != 0) { 1291 msg_info("table %s has changed -- restarting", table); 1292 exit(0); 1293 } 1294 } 1295 1296 /* drop_privileges - drop privileges most of the time */ 1297 1298 static void drop_privileges(char *unused_name, char **unused_argv) 1299 { 1300 set_eugid(var_owner_uid, var_owner_gid); 1301 } 1302 1303 /* pre_init - initialize */ 1304 1305 static void pre_init(char *unused_name, char **unused_argv) 1306 { 1307 flush_init(); 1308 } 1309 1310 MAIL_VERSION_STAMP_DECLARE; 1311 1312 /* main - pass control to the single-threaded skeleton */ 1313 1314 int main(int argc, char **argv) 1315 { 1316 static const CONFIG_TIME_TABLE time_table[] = { 1317 VAR_COMMAND_MAXTIME, DEF_COMMAND_MAXTIME, &var_command_maxtime, 1, 0, 1318 0, 1319 }; 1320 1321 /* 1322 * Fingerprint executables and core dumps. 1323 */ 1324 MAIL_VERSION_STAMP_ALLOCATE; 1325 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, 1332 0); 1333 } 1334