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