| 1 | /* $Cambridge: exim/src/src/transports/pipe.c,v 1.5 2005/05/03 14:20:01 ph10 Exp $ */ |
| 2 | |
| 3 | /************************************************* |
| 4 | * Exim - an Internet mail transport agent * |
| 5 | *************************************************/ |
| 6 | |
| 7 | /* Copyright (c) University of Cambridge 1995 - 2005 */ |
| 8 | /* See the file NOTICE for conditions of use and distribution. */ |
| 9 | |
| 10 | |
| 11 | #include "../exim.h" |
| 12 | #include "pipe.h" |
| 13 | |
| 14 | |
| 15 | |
| 16 | /* Options specific to the pipe transport. They must be in alphabetic |
| 17 | order (note that "_" comes before the lower case letters). Those starting |
| 18 | with "*" are not settable by the user but are used by the option-reading |
| 19 | software for alternative value types. Some options are stored in the transport |
| 20 | instance block so as to be publicly visible; these are flagged with opt_public. |
| 21 | */ |
| 22 | |
| 23 | optionlist pipe_transport_options[] = { |
| 24 | { "allow_commands", opt_stringptr, |
| 25 | (void *)offsetof(pipe_transport_options_block, allow_commands) }, |
| 26 | { "batch_id", opt_stringptr | opt_public, |
| 27 | (void *)offsetof(transport_instance, batch_id) }, |
| 28 | { "batch_max", opt_int | opt_public, |
| 29 | (void *)offsetof(transport_instance, batch_max) }, |
| 30 | { "check_string", opt_stringptr, |
| 31 | (void *)offsetof(pipe_transport_options_block, check_string) }, |
| 32 | { "command", opt_stringptr, |
| 33 | (void *)offsetof(pipe_transport_options_block, cmd) }, |
| 34 | { "environment", opt_stringptr, |
| 35 | (void *)offsetof(pipe_transport_options_block, environment) }, |
| 36 | { "escape_string", opt_stringptr, |
| 37 | (void *)offsetof(pipe_transport_options_block, escape_string) }, |
| 38 | { "freeze_exec_fail", opt_bool, |
| 39 | (void *)offsetof(pipe_transport_options_block, freeze_exec_fail) }, |
| 40 | { "ignore_status", opt_bool, |
| 41 | (void *)offsetof(pipe_transport_options_block, ignore_status) }, |
| 42 | { "log_defer_output", opt_bool | opt_public, |
| 43 | (void *)offsetof(transport_instance, log_defer_output) }, |
| 44 | { "log_fail_output", opt_bool | opt_public, |
| 45 | (void *)offsetof(transport_instance, log_fail_output) }, |
| 46 | { "log_output", opt_bool | opt_public, |
| 47 | (void *)offsetof(transport_instance, log_output) }, |
| 48 | { "max_output", opt_mkint, |
| 49 | (void *)offsetof(pipe_transport_options_block, max_output) }, |
| 50 | { "message_prefix", opt_stringptr, |
| 51 | (void *)offsetof(pipe_transport_options_block, message_prefix) }, |
| 52 | { "message_suffix", opt_stringptr, |
| 53 | (void *)offsetof(pipe_transport_options_block, message_suffix) }, |
| 54 | { "path", opt_stringptr, |
| 55 | (void *)offsetof(pipe_transport_options_block, path) }, |
| 56 | { "pipe_as_creator", opt_bool | opt_public, |
| 57 | (void *)offsetof(transport_instance, deliver_as_creator) }, |
| 58 | { "restrict_to_path", opt_bool, |
| 59 | (void *)offsetof(pipe_transport_options_block, restrict_to_path) }, |
| 60 | { "return_fail_output",opt_bool | opt_public, |
| 61 | (void *)offsetof(transport_instance, return_fail_output) }, |
| 62 | { "return_output", opt_bool | opt_public, |
| 63 | (void *)offsetof(transport_instance, return_output) }, |
| 64 | { "temp_errors", opt_stringptr, |
| 65 | (void *)offsetof(pipe_transport_options_block, temp_errors) }, |
| 66 | { "timeout", opt_time, |
| 67 | (void *)offsetof(pipe_transport_options_block, timeout) }, |
| 68 | { "timeout_defer", opt_bool, |
| 69 | (void *)offsetof(pipe_transport_options_block, timeout_defer) }, |
| 70 | { "umask", opt_octint, |
| 71 | (void *)offsetof(pipe_transport_options_block, umask) }, |
| 72 | { "use_bsmtp", opt_bool, |
| 73 | (void *)offsetof(pipe_transport_options_block, use_bsmtp) }, |
| 74 | { "use_crlf", opt_bool, |
| 75 | (void *)offsetof(pipe_transport_options_block, use_crlf) }, |
| 76 | { "use_shell", opt_bool, |
| 77 | (void *)offsetof(pipe_transport_options_block, use_shell) }, |
| 78 | }; |
| 79 | |
| 80 | /* Size of the options list. An extern variable has to be used so that its |
| 81 | address can appear in the tables drtables.c. */ |
| 82 | |
| 83 | int pipe_transport_options_count = |
| 84 | sizeof(pipe_transport_options)/sizeof(optionlist); |
| 85 | |
| 86 | /* Default private options block for the pipe transport. */ |
| 87 | |
| 88 | pipe_transport_options_block pipe_transport_option_defaults = { |
| 89 | NULL, /* cmd */ |
| 90 | NULL, /* allow_commands */ |
| 91 | NULL, /* environment */ |
| 92 | US"/usr/bin", /* path */ |
| 93 | NULL, /* message_prefix (reset in init if not bsmtp) */ |
| 94 | NULL, /* message_suffix (ditto) */ |
| 95 | US mac_expanded_string(EX_TEMPFAIL) ":" /* temp_errors */ |
| 96 | mac_expanded_string(EX_CANTCREAT), |
| 97 | NULL, /* check_string */ |
| 98 | NULL, /* escape_string */ |
| 99 | 022, /* umask */ |
| 100 | 20480, /* max_output */ |
| 101 | 60*60, /* timeout */ |
| 102 | 0, /* options */ |
| 103 | FALSE, /* freeze_exec_fail */ |
| 104 | FALSE, /* ignore_status */ |
| 105 | FALSE, /* restrict_to_path */ |
| 106 | FALSE, /* timeout_defer */ |
| 107 | FALSE, /* use_shell */ |
| 108 | FALSE, /* use_bsmtp */ |
| 109 | FALSE /* use_crlf */ |
| 110 | }; |
| 111 | |
| 112 | |
| 113 | |
| 114 | /************************************************* |
| 115 | * Initialization entry point * |
| 116 | *************************************************/ |
| 117 | |
| 118 | /* Called for each instance, after its options have been read, to |
| 119 | enable consistency checks to be done, or anything else that needs |
| 120 | to be set up. */ |
| 121 | |
| 122 | void |
| 123 | pipe_transport_init(transport_instance *tblock) |
| 124 | { |
| 125 | pipe_transport_options_block *ob = |
| 126 | (pipe_transport_options_block *)(tblock->options_block); |
| 127 | |
| 128 | /* If pipe_as_creator is set, then uid/gid should not be set. */ |
| 129 | |
| 130 | if (tblock->deliver_as_creator && (tblock->uid_set || tblock->gid_set || |
| 131 | tblock->expand_uid != NULL || tblock->expand_gid != NULL)) |
| 132 | log_write(0, LOG_PANIC_DIE|LOG_CONFIG, |
| 133 | "both pipe_as_creator and an explicit uid/gid are set for the %s " |
| 134 | "transport", tblock->name); |
| 135 | |
| 136 | /* If a fixed uid field is set, then a gid field must also be set. */ |
| 137 | |
| 138 | if (tblock->uid_set && !tblock->gid_set && tblock->expand_gid == NULL) |
| 139 | log_write(0, LOG_PANIC_DIE|LOG_CONFIG, |
| 140 | "user set without group for the %s transport", tblock->name); |
| 141 | |
| 142 | /* Temp_errors must consist only of digits and colons, but there can be |
| 143 | spaces round the colons, so allow them too. */ |
| 144 | |
| 145 | if (ob->temp_errors != NULL && Ustrcmp(ob->temp_errors, "*") != 0) |
| 146 | { |
| 147 | size_t p = Ustrspn(ob->temp_errors, "0123456789: "); |
| 148 | if (ob->temp_errors[p] != 0) |
| 149 | log_write(0, LOG_PANIC_DIE|LOG_CONFIG, |
| 150 | "temp_errors must be a list of numbers or an asterisk for the %s " |
| 151 | "transport", tblock->name); |
| 152 | } |
| 153 | |
| 154 | /* Only one of return_output/return_fail_output or log_output/log_fail_output |
| 155 | should be set. */ |
| 156 | |
| 157 | if (tblock->return_output && tblock->return_fail_output) |
| 158 | log_write(0, LOG_PANIC_DIE|LOG_CONFIG, |
| 159 | "both return_output and return_fail_output set for %s transport", |
| 160 | tblock->name); |
| 161 | |
| 162 | if (tblock->log_output && tblock->log_fail_output) |
| 163 | log_write(0, LOG_PANIC_DIE|LOG_CONFIG, |
| 164 | "both log_output and log_fail_output set for the %s transport", |
| 165 | tblock->name); |
| 166 | |
| 167 | /* If batch SMTP is set, force the check and escape strings, and arrange that |
| 168 | headers are also escaped. */ |
| 169 | |
| 170 | if (ob->use_bsmtp) |
| 171 | { |
| 172 | ob->check_string = US"."; |
| 173 | ob->escape_string = US".."; |
| 174 | ob->options |= topt_escape_headers; |
| 175 | } |
| 176 | |
| 177 | /* If not batch SMTP, and message_prefix or message_suffix are unset, insert |
| 178 | default values for them. */ |
| 179 | |
| 180 | else |
| 181 | { |
| 182 | if (ob->message_prefix == NULL) ob->message_prefix = |
| 183 | US"From ${if def:return_path{$return_path}{MAILER-DAEMON}} ${tod_bsdinbox}\n"; |
| 184 | if (ob->message_suffix == NULL) ob->message_suffix = US"\n"; |
| 185 | } |
| 186 | |
| 187 | /* The restrict_to_path and use_shell options are incompatible */ |
| 188 | |
| 189 | if (ob->restrict_to_path && ob->use_shell) |
| 190 | log_write(0, LOG_PANIC_DIE|LOG_CONFIG, |
| 191 | "both restrict_to_path and use_shell set for %s transport", |
| 192 | tblock->name); |
| 193 | |
| 194 | /* The allow_commands and use_shell options are incompatible */ |
| 195 | |
| 196 | if (ob->allow_commands && ob->use_shell) |
| 197 | log_write(0, LOG_PANIC_DIE|LOG_CONFIG, |
| 198 | "both allow_commands and use_shell set for %s transport", |
| 199 | tblock->name); |
| 200 | |
| 201 | /* Set up the bitwise options for transport_write_message from the various |
| 202 | driver options. Only one of body_only and headers_only can be set. */ |
| 203 | |
| 204 | ob->options |= |
| 205 | (tblock->body_only? topt_no_headers : 0) | |
| 206 | (tblock->headers_only? topt_no_body : 0) | |
| 207 | (tblock->return_path_add? topt_add_return_path : 0) | |
| 208 | (tblock->delivery_date_add? topt_add_delivery_date : 0) | |
| 209 | (tblock->envelope_to_add? topt_add_envelope_to : 0) | |
| 210 | (ob->use_crlf? topt_use_crlf : 0); |
| 211 | } |
| 212 | |
| 213 | |
| 214 | |
| 215 | /************************************************* |
| 216 | * Set up direct (non-shell) command * |
| 217 | *************************************************/ |
| 218 | |
| 219 | /* This function is called when a command line is to be parsed by the transport |
| 220 | and executed directly, without the use of /bin/sh. |
| 221 | |
| 222 | Arguments: |
| 223 | argvptr pointer to anchor for argv vector |
| 224 | cmd points to the command string |
| 225 | expand_arguments true if expansion is to occur |
| 226 | expand_fail error if expansion fails |
| 227 | addr chain of addresses |
| 228 | tname the transport name |
| 229 | ob the transport options block |
| 230 | |
| 231 | Returns: TRUE if all went well; otherwise an error will be |
| 232 | set in the first address and FALSE returned |
| 233 | */ |
| 234 | |
| 235 | static BOOL |
| 236 | set_up_direct_command(uschar ***argvptr, uschar *cmd, BOOL expand_arguments, |
| 237 | int expand_fail, address_item *addr, uschar *tname, |
| 238 | pipe_transport_options_block *ob) |
| 239 | { |
| 240 | BOOL permitted = FALSE; |
| 241 | uschar **argv; |
| 242 | uschar buffer[64]; |
| 243 | |
| 244 | /* Set up "transport <name>" to be put in any error messages, and then |
| 245 | call the common function for creating an argument list and expanding |
| 246 | the items if necessary. If it fails, this function fails (error information |
| 247 | is in the addresses). */ |
| 248 | |
| 249 | sprintf(CS buffer, "%.50s transport", tname); |
| 250 | if (!transport_set_up_command(argvptr, cmd, expand_arguments, expand_fail, |
| 251 | addr, buffer, NULL)) |
| 252 | return FALSE; |
| 253 | |
| 254 | /* Point to the set-up arguments. */ |
| 255 | |
| 256 | argv = *argvptr; |
| 257 | |
| 258 | /* If allow_commands is set, see if the command is in the permitted list. */ |
| 259 | |
| 260 | if (ob->allow_commands != NULL) |
| 261 | { |
| 262 | int sep = 0; |
| 263 | uschar *s, *p; |
| 264 | uschar buffer[256]; |
| 265 | |
| 266 | s = expand_string(ob->allow_commands); |
| 267 | if (s == NULL) |
| 268 | { |
| 269 | addr->transport_return = DEFER; |
| 270 | addr->message = string_sprintf("failed to expand string \"%s\" " |
| 271 | "for %s transport: %s", ob->allow_commands, tname, expand_string_message); |
| 272 | return FALSE; |
| 273 | } |
| 274 | |
| 275 | while ((p = string_nextinlist(&s, &sep, buffer, sizeof(buffer))) != NULL) |
| 276 | { |
| 277 | if (Ustrcmp(p, argv[0]) == 0) { permitted = TRUE; break; } |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | /* If permitted is TRUE it means the command was found in the allowed list, and |
| 282 | no further checks are done. If permitted = FALSE, it either means |
| 283 | allow_commands wasn't set, or that the command didn't match anything in the |
| 284 | list. In both cases, if restrict_to_path is set, we fail if the command |
| 285 | contains any slashes, but if restrict_to_path is not set, we must fail the |
| 286 | command only if allow_commands is set. */ |
| 287 | |
| 288 | if (!permitted) |
| 289 | { |
| 290 | if (ob->restrict_to_path) |
| 291 | { |
| 292 | if (Ustrchr(argv[0], '/') != NULL) |
| 293 | { |
| 294 | addr->transport_return = FAIL; |
| 295 | addr->message = string_sprintf("\"/\" found in \"%s\" (command for %s " |
| 296 | "transport) - failed for security reasons", cmd, tname); |
| 297 | return FALSE; |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | else if (ob->allow_commands != NULL) |
| 302 | { |
| 303 | addr->transport_return = FAIL; |
| 304 | addr->message = string_sprintf("\"%s\" command not permitted by %s " |
| 305 | "transport", argv[0], tname); |
| 306 | return FALSE; |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | /* If the command is not an absolute path, search the PATH directories |
| 311 | for it. */ |
| 312 | |
| 313 | if (argv[0][0] != '/') |
| 314 | { |
| 315 | int sep = 0; |
| 316 | uschar *p; |
| 317 | uschar *listptr = ob->path; |
| 318 | uschar buffer[1024]; |
| 319 | |
| 320 | while ((p = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))) != NULL) |
| 321 | { |
| 322 | struct stat statbuf; |
| 323 | sprintf(CS big_buffer, "%.256s/%.256s", p, argv[0]); |
| 324 | if (Ustat(big_buffer, &statbuf) == 0) |
| 325 | { |
| 326 | argv[0] = string_copy(big_buffer); |
| 327 | break; |
| 328 | } |
| 329 | } |
| 330 | if (p == NULL) |
| 331 | { |
| 332 | addr->transport_return = FAIL; |
| 333 | addr->message = string_sprintf("\"%s\" command not found for %s transport", |
| 334 | argv[0], tname); |
| 335 | return FALSE; |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | return TRUE; |
| 340 | } |
| 341 | |
| 342 | |
| 343 | /************************************************* |
| 344 | * Set up shell command * |
| 345 | *************************************************/ |
| 346 | |
| 347 | /* This function is called when a command line is to be passed to /bin/sh |
| 348 | without parsing inside the transport. |
| 349 | |
| 350 | Arguments: |
| 351 | argvptr pointer to anchor for argv vector |
| 352 | cmd points to the command string |
| 353 | expand_arguments true if expansion is to occur |
| 354 | expand_fail error if expansion fails |
| 355 | addr chain of addresses |
| 356 | tname the transport name |
| 357 | |
| 358 | Returns: TRUE if all went well; otherwise an error will be |
| 359 | set in the first address and FALSE returned |
| 360 | */ |
| 361 | |
| 362 | static BOOL |
| 363 | set_up_shell_command(uschar ***argvptr, uschar *cmd, BOOL expand_arguments, |
| 364 | int expand_fail, address_item *addr, uschar *tname) |
| 365 | { |
| 366 | uschar **argv; |
| 367 | |
| 368 | *argvptr = argv = store_get((4)*sizeof(uschar *)); |
| 369 | |
| 370 | argv[0] = US"/bin/sh"; |
| 371 | argv[1] = US"-c"; |
| 372 | |
| 373 | /* We have to take special action to handle the special "variable" called |
| 374 | $pipe_addresses, which is not recognized by the normal expansion function. */ |
| 375 | |
| 376 | DEBUG(D_transport) |
| 377 | debug_printf("shell pipe command before expansion:\n %s\n", cmd); |
| 378 | |
| 379 | if (expand_arguments) |
| 380 | { |
| 381 | uschar *s = cmd; |
| 382 | uschar *p = Ustrstr(cmd, "pipe_addresses"); |
| 383 | |
| 384 | if (p != NULL && ( |
| 385 | (p > cmd && p[-1] == '$') || |
| 386 | (p > cmd + 1 && p[-2] == '$' && p[-1] == '{' && p[14] == '}'))) |
| 387 | { |
| 388 | address_item *ad; |
| 389 | uschar *q = p + 14; |
| 390 | int size = Ustrlen(cmd) + 64; |
| 391 | int offset; |
| 392 | |
| 393 | if (p[-1] == '{') { q++; p--; } |
| 394 | |
| 395 | s = store_get(size); |
| 396 | offset = p - cmd - 1; |
| 397 | Ustrncpy(s, cmd, offset); |
| 398 | |
| 399 | for (ad = addr; ad != NULL; ad = ad->next) |
| 400 | { |
| 401 | if (ad != addr) string_cat(s, &size, &offset, US" ", 1); |
| 402 | string_cat(s, &size, &offset, ad->address, Ustrlen(ad->address)); |
| 403 | } |
| 404 | |
| 405 | string_cat(s, &size, &offset, q, Ustrlen(q)); |
| 406 | s[offset] = 0; |
| 407 | } |
| 408 | |
| 409 | /* Allow $recipients in the expansion iff it comes from a system filter */ |
| 410 | |
| 411 | enable_dollar_recipients = addr != NULL && |
| 412 | addr->parent != NULL && |
| 413 | Ustrcmp(addr->parent->address, "system-filter") == 0; |
| 414 | argv[2] = expand_string(s); |
| 415 | enable_dollar_recipients = FALSE; |
| 416 | |
| 417 | if (argv[2] == NULL) |
| 418 | { |
| 419 | addr->transport_return = search_find_defer? DEFER : expand_fail; |
| 420 | addr->message = string_sprintf("Expansion of command \"%s\" " |
| 421 | "in %s transport failed: %s", |
| 422 | cmd, tname, expand_string_message); |
| 423 | return FALSE; |
| 424 | } |
| 425 | |
| 426 | DEBUG(D_transport) |
| 427 | debug_printf("shell pipe command after expansion:\n %s\n", argv[2]); |
| 428 | } |
| 429 | else argv[2] = cmd; |
| 430 | |
| 431 | argv[3] = (uschar *)0; |
| 432 | return TRUE; |
| 433 | } |
| 434 | |
| 435 | |
| 436 | |
| 437 | |
| 438 | /************************************************* |
| 439 | * Main entry point * |
| 440 | *************************************************/ |
| 441 | |
| 442 | /* See local README for interface details. This transport always returns FALSE, |
| 443 | indicating that the status in the first address is the status for all addresses |
| 444 | in a batch. */ |
| 445 | |
| 446 | BOOL |
| 447 | pipe_transport_entry( |
| 448 | transport_instance *tblock, /* data for this instantiation */ |
| 449 | address_item *addr) /* address(es) we are working on */ |
| 450 | { |
| 451 | pid_t pid, outpid; |
| 452 | int fd_in, fd_out, rc; |
| 453 | int envcount = 0; |
| 454 | int envsep = 0; |
| 455 | int expand_fail; |
| 456 | pipe_transport_options_block *ob = |
| 457 | (pipe_transport_options_block *)(tblock->options_block); |
| 458 | int timeout = ob->timeout; |
| 459 | BOOL written_ok = FALSE; |
| 460 | BOOL expand_arguments; |
| 461 | uschar **argv; |
| 462 | uschar *envp[50]; |
| 463 | uschar *envlist = ob->environment; |
| 464 | uschar *cmd, *ss; |
| 465 | uschar *eol = (ob->use_crlf)? US"\r\n" : US"\n"; |
| 466 | |
| 467 | DEBUG(D_transport) debug_printf("%s transport entered\n", tblock->name); |
| 468 | |
| 469 | /* Set up for the good case */ |
| 470 | |
| 471 | addr->transport_return = OK; |
| 472 | addr->basic_errno = 0; |
| 473 | |
| 474 | /* Pipes are not accepted as general addresses, but they can be generated from |
| 475 | .forward files or alias files. In those cases, the pfr flag is set, and the |
| 476 | command to be obeyed is pointed to by addr->local_part; it starts with the pipe |
| 477 | symbol. In other cases, the command is supplied as one of the pipe transport's |
| 478 | options. */ |
| 479 | |
| 480 | if (testflag(addr, af_pfr) && addr->local_part[0] == '|') |
| 481 | { |
| 482 | cmd = addr->local_part + 1; |
| 483 | while (isspace(*cmd)) cmd++; |
| 484 | expand_arguments = testflag(addr, af_expand_pipe); |
| 485 | expand_fail = FAIL; |
| 486 | } |
| 487 | else |
| 488 | { |
| 489 | cmd = ob->cmd; |
| 490 | expand_arguments = TRUE; |
| 491 | expand_fail = PANIC; |
| 492 | } |
| 493 | |
| 494 | /* If no command has been supplied, we are in trouble. */ |
| 495 | |
| 496 | if (cmd == NULL) |
| 497 | { |
| 498 | addr->transport_return = DEFER; |
| 499 | addr->message = string_sprintf("no command specified for %s transport", |
| 500 | tblock->name); |
| 501 | return FALSE; |
| 502 | } |
| 503 | |
| 504 | /* When a pipe is set up by a filter file, there may be values for $thisaddress |
| 505 | and numerical the variables in existence. These are passed in |
| 506 | addr->pipe_expandn for use here. */ |
| 507 | |
| 508 | if (expand_arguments && addr->pipe_expandn != NULL) |
| 509 | { |
| 510 | uschar **ss = addr->pipe_expandn; |
| 511 | expand_nmax = -1; |
| 512 | if (*ss != NULL) filter_thisaddress = *ss++; |
| 513 | while (*ss != NULL) |
| 514 | { |
| 515 | expand_nstring[++expand_nmax] = *ss; |
| 516 | expand_nlength[expand_nmax] = Ustrlen(*ss++); |
| 517 | } |
| 518 | } |
| 519 | |
| 520 | /* The default way of processing the command is to split it up into arguments |
| 521 | here, and run it directly. This offers some security advantages. However, there |
| 522 | are installations that want by default to run commands under /bin/sh always, so |
| 523 | there is an option to do that. */ |
| 524 | |
| 525 | if (ob->use_shell) |
| 526 | { |
| 527 | if (!set_up_shell_command(&argv, cmd, expand_arguments, expand_fail, addr, |
| 528 | tblock->name)) return FALSE; |
| 529 | } |
| 530 | else if (!set_up_direct_command(&argv, cmd, expand_arguments, expand_fail, addr, |
| 531 | tblock->name, ob)) return FALSE; |
| 532 | |
| 533 | expand_nmax = -1; /* Reset */ |
| 534 | filter_thisaddress = NULL; |
| 535 | |
| 536 | /* Set up the environment for the command. */ |
| 537 | |
| 538 | envp[envcount++] = string_sprintf("LOCAL_PART=%s", deliver_localpart); |
| 539 | envp[envcount++] = string_sprintf("LOGNAME=%s", deliver_localpart); |
| 540 | envp[envcount++] = string_sprintf("USER=%s", deliver_localpart); |
| 541 | envp[envcount++] = string_sprintf("LOCAL_PART_PREFIX=%#s", |
| 542 | deliver_localpart_prefix); |
| 543 | envp[envcount++] = string_sprintf("LOCAL_PART_SUFFIX=%#s", |
| 544 | deliver_localpart_suffix); |
| 545 | envp[envcount++] = string_sprintf("DOMAIN=%s", deliver_domain); |
| 546 | envp[envcount++] = string_sprintf("HOME=%#s", deliver_home); |
| 547 | envp[envcount++] = string_sprintf("MESSAGE_ID=%s", message_id); |
| 548 | envp[envcount++] = string_sprintf("PATH=%s", ob->path); |
| 549 | envp[envcount++] = string_sprintf("RECIPIENT=%#s%#s%#s@%#s", |
| 550 | deliver_localpart_prefix, deliver_localpart, deliver_localpart_suffix, |
| 551 | deliver_domain); |
| 552 | envp[envcount++] = string_sprintf("QUALIFY_DOMAIN=%s", qualify_domain_sender); |
| 553 | envp[envcount++] = string_sprintf("SENDER=%s", sender_address); |
| 554 | envp[envcount++] = US"SHELL=/bin/sh"; |
| 555 | |
| 556 | if (addr->host_list != NULL) |
| 557 | envp[envcount++] = string_sprintf("HOST=%s", addr->host_list->name); |
| 558 | |
| 559 | if (timestamps_utc) envp[envcount++] = US"TZ=UTC"; |
| 560 | else if (timezone_string != NULL && timezone_string[0] != 0) |
| 561 | envp[envcount++] = string_sprintf("TZ=%s", timezone_string); |
| 562 | |
| 563 | /* Add any requested items */ |
| 564 | |
| 565 | if (envlist != NULL) |
| 566 | { |
| 567 | envlist = expand_string(envlist); |
| 568 | if (envlist == NULL) |
| 569 | { |
| 570 | addr->transport_return = DEFER; |
| 571 | addr->message = string_sprintf("failed to expand string \"%s\" " |
| 572 | "for %s transport: %s", ob->environment, tblock->name, |
| 573 | expand_string_message); |
| 574 | return FALSE; |
| 575 | } |
| 576 | } |
| 577 | |
| 578 | while ((ss = string_nextinlist(&envlist, &envsep, big_buffer, big_buffer_size)) |
| 579 | != NULL) |
| 580 | { |
| 581 | if (envcount > sizeof(envp)/sizeof(uschar *) - 2) |
| 582 | { |
| 583 | addr->transport_return = DEFER; |
| 584 | addr->message = string_sprintf("too many environment settings for " |
| 585 | "%s transport", tblock->name); |
| 586 | return FALSE; |
| 587 | } |
| 588 | envp[envcount++] = string_copy(ss); |
| 589 | } |
| 590 | |
| 591 | envp[envcount] = NULL; |
| 592 | |
| 593 | /* If the -N option is set, can't do any more. */ |
| 594 | |
| 595 | if (dont_deliver) |
| 596 | { |
| 597 | DEBUG(D_transport) |
| 598 | debug_printf("*** delivery by %s transport bypassed by -N option", |
| 599 | tblock->name); |
| 600 | return FALSE; |
| 601 | } |
| 602 | |
| 603 | |
| 604 | /* Handling the output from the pipe is tricky. If a file for catching this |
| 605 | output is provided, we could in theory just hand that fd over to the process, |
| 606 | but this isn't very safe because it might loop and carry on writing for |
| 607 | ever (which is exactly what happened in early versions of Exim). Therefore we |
| 608 | use the standard child_open() function, which creates pipes. We can then read |
| 609 | our end of the output pipe and count the number of bytes that come through, |
| 610 | chopping the sub-process if it exceeds some limit. |
| 611 | |
| 612 | However, this means we want to run a sub-process with both its input and output |
| 613 | attached to pipes. We can't handle that easily from a single parent process |
| 614 | using straightforward code such as the transport_write_message() function |
| 615 | because the subprocess might not be reading its input because it is trying to |
| 616 | write to a full output pipe. The complication of redesigning the world to |
| 617 | handle this is too great - simpler just to run another process to do the |
| 618 | reading of the output pipe. */ |
| 619 | |
| 620 | |
| 621 | /* As this is a local transport, we are already running with the required |
| 622 | uid/gid and current directory. Request that the new process be a process group |
| 623 | leader, so we can kill it and all its children on a timeout. */ |
| 624 | |
| 625 | if ((pid = child_open(argv, envp, ob->umask, &fd_in, &fd_out, TRUE)) < 0) |
| 626 | { |
| 627 | addr->transport_return = DEFER; |
| 628 | addr->message = string_sprintf( |
| 629 | "Failed to create child process for %s transport: %s", tblock->name, |
| 630 | strerror(errno)); |
| 631 | return FALSE; |
| 632 | } |
| 633 | |
| 634 | /* Now fork a process to handle the output that comes down the pipe. */ |
| 635 | |
| 636 | if ((outpid = fork()) < 0) |
| 637 | { |
| 638 | addr->basic_errno = errno; |
| 639 | addr->transport_return = DEFER; |
| 640 | addr->message = string_sprintf( |
| 641 | "Failed to create process for handling output in %s transport", |
| 642 | tblock->name); |
| 643 | close(fd_in); |
| 644 | close(fd_out); |
| 645 | return FALSE; |
| 646 | } |
| 647 | |
| 648 | /* This is the code for the output-handling subprocess. Read from the pipe |
| 649 | in chunks, and write to the return file if one is provided. Keep track of |
| 650 | the number of bytes handled. If the limit is exceeded, try to kill the |
| 651 | subprocess group, and in any case close the pipe and exit, which should cause |
| 652 | the subprocess to fail. */ |
| 653 | |
| 654 | if (outpid == 0) |
| 655 | { |
| 656 | int count = 0; |
| 657 | close(fd_in); |
| 658 | set_process_info("reading output from |%s", cmd); |
| 659 | while ((rc = read(fd_out, big_buffer, big_buffer_size)) > 0) |
| 660 | { |
| 661 | if (addr->return_file >= 0) |
| 662 | write(addr->return_file, big_buffer, rc); |
| 663 | count += rc; |
| 664 | if (count > ob->max_output) |
| 665 | { |
| 666 | uschar *message = US"\n\n*** Too much output - remainder discarded ***\n"; |
| 667 | DEBUG(D_transport) debug_printf("Too much output from pipe - killed\n"); |
| 668 | if (addr->return_file >= 0) |
| 669 | write(addr->return_file, message, Ustrlen(message)); |
| 670 | killpg(pid, SIGKILL); |
| 671 | break; |
| 672 | } |
| 673 | } |
| 674 | close(fd_out); |
| 675 | _exit(0); |
| 676 | } |
| 677 | |
| 678 | close(fd_out); /* Not used in this process */ |
| 679 | |
| 680 | |
| 681 | /* Carrying on now with the main parent process. Attempt to write the message |
| 682 | to it down the pipe. It is a fallacy to think that you can detect write errors |
| 683 | when the sub-process fails to read the pipe. The parent process may complete |
| 684 | writing and close the pipe before the sub-process completes. We could sleep a |
| 685 | bit here to let the sub-process get going, but it may still not complete. So we |
| 686 | ignore all writing errors. (When in the test harness, we do do a short sleep so |
| 687 | any debugging output is likely to be in the same order.) */ |
| 688 | |
| 689 | if (running_in_test_harness) millisleep(500); |
| 690 | |
| 691 | DEBUG(D_transport) debug_printf("Writing message to pipe\n"); |
| 692 | |
| 693 | /* Arrange to time out writes if there is a timeout set. */ |
| 694 | |
| 695 | if (timeout > 0) |
| 696 | { |
| 697 | sigalrm_seen = FALSE; |
| 698 | transport_write_timeout = timeout; |
| 699 | } |
| 700 | |
| 701 | /* Reset the counter of bytes written */ |
| 702 | |
| 703 | transport_count = 0; |
| 704 | |
| 705 | /* First write any configured prefix information */ |
| 706 | |
| 707 | if (ob->message_prefix != NULL) |
| 708 | { |
| 709 | uschar *prefix = expand_string(ob->message_prefix); |
| 710 | if (prefix == NULL) |
| 711 | { |
| 712 | addr->transport_return = search_find_defer? DEFER : PANIC; |
| 713 | addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s " |
| 714 | "transport) failed: %s", ob->message_prefix, tblock->name, |
| 715 | expand_string_message); |
| 716 | return FALSE; |
| 717 | } |
| 718 | if (!transport_write_block(fd_in, prefix, Ustrlen(prefix))) |
| 719 | goto END_WRITE; |
| 720 | } |
| 721 | |
| 722 | /* If the use_bsmtp option is set, we need to write SMTP prefix information. |
| 723 | The various different values for batching are handled outside; if there is more |
| 724 | than one address available here, all must be included. Force SMTP dot-handling. |
| 725 | */ |
| 726 | |
| 727 | if (ob->use_bsmtp) |
| 728 | { |
| 729 | address_item *a; |
| 730 | |
| 731 | if (!transport_write_string(fd_in, "MAIL FROM:<%s>%s", return_path, eol)) |
| 732 | goto END_WRITE; |
| 733 | |
| 734 | for (a = addr; a != NULL; a = a->next) |
| 735 | { |
| 736 | if (!transport_write_string(fd_in, |
| 737 | "RCPT TO:<%s>%s", |
| 738 | transport_rcpt_address(a, tblock->rcpt_include_affixes), |
| 739 | eol)) |
| 740 | goto END_WRITE; |
| 741 | } |
| 742 | |
| 743 | if (!transport_write_string(fd_in, "DATA%s", eol)) goto END_WRITE; |
| 744 | } |
| 745 | |
| 746 | /* Now the actual message - the options were set at initialization time */ |
| 747 | |
| 748 | if (!transport_write_message(addr, fd_in, ob->options, 0, tblock->add_headers, |
| 749 | tblock->remove_headers, ob->check_string, ob->escape_string, |
| 750 | tblock->rewrite_rules, tblock->rewrite_existflags)) |
| 751 | goto END_WRITE; |
| 752 | |
| 753 | /* Now any configured suffix */ |
| 754 | |
| 755 | if (ob->message_suffix != NULL) |
| 756 | { |
| 757 | uschar *suffix = expand_string(ob->message_suffix); |
| 758 | if (suffix == NULL) |
| 759 | { |
| 760 | addr->transport_return = search_find_defer? DEFER : PANIC; |
| 761 | addr->message = string_sprintf("Expansion of \"%s\" (suffix for %s " |
| 762 | "transport) failed: %s", ob->message_suffix, tblock->name, |
| 763 | expand_string_message); |
| 764 | return FALSE; |
| 765 | } |
| 766 | if (!transport_write_block(fd_in, suffix, Ustrlen(suffix))) |
| 767 | goto END_WRITE; |
| 768 | } |
| 769 | |
| 770 | /* If local_smtp, write the terminating dot. */ |
| 771 | |
| 772 | if (ob->use_bsmtp && !transport_write_string(fd_in, ".%s", eol)) |
| 773 | goto END_WRITE; |
| 774 | |
| 775 | /* Flag all writing completed successfully. */ |
| 776 | |
| 777 | written_ok = TRUE; |
| 778 | |
| 779 | /* Come here if there are errors during writing. */ |
| 780 | |
| 781 | END_WRITE: |
| 782 | |
| 783 | /* OK, the writing is now all done. Close the pipe. */ |
| 784 | |
| 785 | (void) close(fd_in); |
| 786 | |
| 787 | /* Handle errors during writing. For timeouts, set the timeout for waiting for |
| 788 | the child process to 1 second. If the process at the far end of the pipe died |
| 789 | without reading all of it, we expect an EPIPE error, which should be ignored. |
| 790 | We used also to ignore WRITEINCOMPLETE but the writing function is now cleverer |
| 791 | at handling OS where the death of a pipe doesn't give EPIPE immediately. See |
| 792 | comments therein. */ |
| 793 | |
| 794 | if (!written_ok) |
| 795 | { |
| 796 | if (errno == ETIMEDOUT) |
| 797 | { |
| 798 | addr->message = string_sprintf("%stimeout while writing to pipe", |
| 799 | transport_filter_timed_out? "transport filter " : ""); |
| 800 | addr->transport_return = ob->timeout_defer? DEFER : FAIL; |
| 801 | timeout = 1; |
| 802 | } |
| 803 | else if (errno == EPIPE) |
| 804 | { |
| 805 | debug_printf("transport error EPIPE ignored\n"); |
| 806 | } |
| 807 | else |
| 808 | { |
| 809 | addr->transport_return = PANIC; |
| 810 | addr->basic_errno = errno; |
| 811 | if (errno == ERRNO_CHHEADER_FAIL) |
| 812 | addr->message = |
| 813 | string_sprintf("Failed to expand headers_add or headers_remove: %s", |
| 814 | expand_string_message); |
| 815 | else if (errno == ERRNO_FILTER_FAIL) |
| 816 | addr->message = string_sprintf("Transport filter process failed (%d)%s", |
| 817 | addr->more_errno, |
| 818 | (addr->more_errno == EX_EXECFAILED)? ": unable to execute command" : ""); |
| 819 | else if (errno == ERRNO_WRITEINCOMPLETE) |
| 820 | addr->message = string_sprintf("Failed repeatedly to write data"); |
| 821 | else |
| 822 | addr->message = string_sprintf("Error %d", errno); |
| 823 | return FALSE; |
| 824 | } |
| 825 | } |
| 826 | |
| 827 | /* Wait for the child process to complete and take action if the returned |
| 828 | status is nonzero. The timeout will be just 1 second if any of the writes |
| 829 | above timed out. */ |
| 830 | |
| 831 | if ((rc = child_close(pid, timeout)) != 0) |
| 832 | { |
| 833 | /* The process did not complete in time; kill its process group and fail |
| 834 | the delivery. It appears to be necessary to kill the output process too, as |
| 835 | otherwise it hangs on for some time if the actual pipe process is sleeping. |
| 836 | (At least, that's what I observed on Solaris 2.5.1.) Since we are failing |
| 837 | the delivery, that shouldn't cause any problem. */ |
| 838 | |
| 839 | if (rc == -256) |
| 840 | { |
| 841 | killpg(pid, SIGKILL); |
| 842 | kill(outpid, SIGKILL); |
| 843 | addr->transport_return = ob->timeout_defer? DEFER : FAIL; |
| 844 | addr->message = string_sprintf("pipe delivery process timed out"); |
| 845 | } |
| 846 | |
| 847 | /* Wait() failed. */ |
| 848 | |
| 849 | else if (rc == -257) |
| 850 | { |
| 851 | addr->transport_return = PANIC; |
| 852 | addr->message = string_sprintf("Wait() failed for child process of %s " |
| 853 | "transport: %s", tblock->name, strerror(errno)); |
| 854 | } |
| 855 | |
| 856 | /* Either the process completed, but yielded a non-zero (necessarily |
| 857 | positive) status, or the process was terminated by a signal (rc will contain |
| 858 | the negation of the signal number). Treat killing by signal as failure unless |
| 859 | status is being ignored. */ |
| 860 | |
| 861 | else if (rc < 0) |
| 862 | { |
| 863 | if (!ob->ignore_status) |
| 864 | { |
| 865 | addr->transport_return = FAIL; |
| 866 | addr->message = string_sprintf("Child process of %s transport (running " |
| 867 | "command \"%s\") was terminated by signal %d (%s)", tblock->name, cmd, |
| 868 | -rc, os_strsignal(-rc)); |
| 869 | } |
| 870 | } |
| 871 | |
| 872 | /* For positive values (process terminated with non-zero status), we need a |
| 873 | status code to request deferral. A number of systems contain the following |
| 874 | line in sysexits.h: |
| 875 | |
| 876 | #define EX_TEMPFAIL 75 |
| 877 | |
| 878 | with the description |
| 879 | |
| 880 | EX_TEMPFAIL -- temporary failure, indicating something that |
| 881 | is not really an error. In sendmail, this means |
| 882 | that a mailer (e.g.) could not create a connection, |
| 883 | and the request should be reattempted later. |
| 884 | |
| 885 | Based on this, we use exit code EX_TEMPFAIL as a default to mean "defer" when |
| 886 | not ignoring the returned status. However, there is now an option that |
| 887 | contains a list of temporary codes, with TEMPFAIL and CANTCREAT as defaults. |
| 888 | |
| 889 | Another case that needs special treatment is if execve() failed (typically |
| 890 | the command that was given is a non-existent path). By default this is |
| 891 | treated as just another failure, but if freeze_exec_fail is set, the reaction |
| 892 | is to freeze the message rather than bounce the address. Exim used to signal |
| 893 | this failure with EX_UNAVAILABLE, which is definined in many systems as |
| 894 | |
| 895 | #define EX_UNAVAILABLE 69 |
| 896 | |
| 897 | with the description |
| 898 | |
| 899 | EX_UNAVAILABLE -- A service is unavailable. This can occur |
| 900 | if a support program or file does not exist. This |
| 901 | can also be used as a catchall message when something |
| 902 | you wanted to do doesn't work, but you don't know why. |
| 903 | |
| 904 | However, this can be confused with a command that actually returns 69 because |
| 905 | something *it* wanted is unavailable. At release 4.21, Exim was changed to |
| 906 | use return code 127 instead, because this is what the shell returns when it |
| 907 | is unable to exec a command. We define it as EX_EXECFAILED, and use it in |
| 908 | child.c to signal execve() failure and other unexpected failures such as |
| 909 | setuid() not working - though that won't be the case here because we aren't |
| 910 | changing uid. */ |
| 911 | |
| 912 | else |
| 913 | { |
| 914 | /* Always handle execve() failure specially if requested to */ |
| 915 | |
| 916 | if (ob->freeze_exec_fail && (rc == EX_EXECFAILED)) |
| 917 | { |
| 918 | addr->transport_return = DEFER; |
| 919 | addr->special_action = SPECIAL_FREEZE; |
| 920 | addr->message = string_sprintf("pipe process failed to exec \"%s\"", |
| 921 | cmd); |
| 922 | } |
| 923 | |
| 924 | /* Otherwise take action only if not ignoring status */ |
| 925 | |
| 926 | else if (!ob->ignore_status) |
| 927 | { |
| 928 | uschar *ss; |
| 929 | int size, ptr, i; |
| 930 | |
| 931 | /* If temp_errors is "*" all codes are temporary. Initializion checks |
| 932 | that it's either "*" or a list of numbers. If not "*", scan the list of |
| 933 | temporary failure codes; if any match, the result is DEFER. */ |
| 934 | |
| 935 | if (ob->temp_errors[0] == '*') |
| 936 | addr->transport_return = DEFER; |
| 937 | |
| 938 | else |
| 939 | { |
| 940 | uschar *s = ob->temp_errors; |
| 941 | uschar *p; |
| 942 | uschar buffer[64]; |
| 943 | int sep = 0; |
| 944 | |
| 945 | addr->transport_return = FAIL; |
| 946 | while ((p = string_nextinlist(&s,&sep,buffer,sizeof(buffer))) != NULL) |
| 947 | { |
| 948 | if (rc == Uatoi(p)) { addr->transport_return = DEFER; break; } |
| 949 | } |
| 950 | } |
| 951 | |
| 952 | /* Ensure the message contains the expanded command and arguments. This |
| 953 | doesn't have to be brilliantly efficient - it is an error situation. */ |
| 954 | |
| 955 | addr->message = string_sprintf("Child process of %s transport returned " |
| 956 | "%d", tblock->name, rc); |
| 957 | |
| 958 | ptr = Ustrlen(addr->message); |
| 959 | size = ptr + 1; |
| 960 | |
| 961 | /* If the return code is > 128, it often means that a shell command |
| 962 | was terminated by a signal. */ |
| 963 | |
| 964 | ss = (rc > 128)? |
| 965 | string_sprintf("(could mean shell command ended by signal %d (%s))", |
| 966 | rc-128, os_strsignal(rc-128)) : |
| 967 | US os_strexit(rc); |
| 968 | |
| 969 | if (*ss != 0) |
| 970 | { |
| 971 | addr->message = string_cat(addr->message, &size, &ptr, US" ", 1); |
| 972 | addr->message = string_cat(addr->message, &size, &ptr, |
| 973 | ss, Ustrlen(ss)); |
| 974 | } |
| 975 | |
| 976 | /* Now add the command and arguments */ |
| 977 | |
| 978 | addr->message = string_cat(addr->message, &size, &ptr, |
| 979 | US" from command:", 14); |
| 980 | |
| 981 | for (i = 0; i < sizeof(argv)/sizeof(int *) && argv[i] != NULL; i++) |
| 982 | { |
| 983 | BOOL quote = FALSE; |
| 984 | addr->message = string_cat(addr->message, &size, &ptr, US" ", 1); |
| 985 | if (Ustrpbrk(argv[i], " \t") != NULL) |
| 986 | { |
| 987 | quote = TRUE; |
| 988 | addr->message = string_cat(addr->message, &size, &ptr, US"\"", 1); |
| 989 | } |
| 990 | addr->message = string_cat(addr->message, &size, &ptr, argv[i], |
| 991 | Ustrlen(argv[i])); |
| 992 | if (quote) |
| 993 | addr->message = string_cat(addr->message, &size, &ptr, US"\"", 1); |
| 994 | } |
| 995 | addr->message[ptr] = 0; /* Ensure concatenated string terminated */ |
| 996 | } |
| 997 | } |
| 998 | } |
| 999 | |
| 1000 | /* Ensure all subprocesses (in particular, the output handling process) |
| 1001 | are complete before we pass this point. */ |
| 1002 | |
| 1003 | while (wait(&rc) >= 0); |
| 1004 | |
| 1005 | DEBUG(D_transport) debug_printf("%s transport yielded %d\n", tblock->name, |
| 1006 | addr->transport_return); |
| 1007 | |
| 1008 | /* If there has been a problem, the message in addr->message contains details |
| 1009 | of the pipe command. We don't want to expose these to the world, so we set up |
| 1010 | something bland to return to the sender. */ |
| 1011 | |
| 1012 | if (addr->transport_return != OK) |
| 1013 | addr->user_message = US"local delivery failed"; |
| 1014 | |
| 1015 | return FALSE; |
| 1016 | } |
| 1017 | |
| 1018 | /* End of transport/pipe.c */ |