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