X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/53947857fdb3c00bb673f6d2ac326dc4ccf01c6e..700d22f3fc0cc559170e8085a1b799b61dceb738:/src/src/transport.c diff --git a/src/src/transport.c b/src/src/transport.c index 1a70b6f32..7dd1afb85 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2009 */ +/* Copyright (c) University of Cambridge 1995 - 2012 */ /* See the file NOTICE for conditions of use and distribution. */ /* General functions concerned with transportation, and generic options for all @@ -68,11 +68,11 @@ optionlist optionlist_transports[] = { (void *)(offsetof(transport_instance, envelope_to_add)) }, { "group", opt_expand_gid|opt_public, (void *)offsetof(transport_instance, gid) }, - { "headers_add", opt_stringptr|opt_public, + { "headers_add", opt_stringptr|opt_public|opt_rep_str, (void *)offsetof(transport_instance, add_headers) }, { "headers_only", opt_bool|opt_public, (void *)offsetof(transport_instance, headers_only) }, - { "headers_remove", opt_stringptr|opt_public, + { "headers_remove", opt_stringptr|opt_public|opt_rep_str, (void *)offsetof(transport_instance, remove_headers) }, { "headers_rewrite", opt_rewrite|opt_public, (void *)offsetof(transport_instance, headers_rewrite) }, @@ -219,7 +219,7 @@ for (i = 0; i < 100; i++) if (transport_write_timeout <= 0) /* No timeout wanted */ { #ifdef SUPPORT_TLS - if (tls_active == fd) rc = tls_write(block, len); else + if (tls_out.active == fd) rc = tls_write(FALSE, block, len); else #endif rc = write(fd, block, len); save_errno = errno; @@ -231,7 +231,7 @@ for (i = 0; i < 100; i++) { alarm(local_timeout); #ifdef SUPPORT_TLS - if (tls_active == fd) rc = tls_write(block, len); else + if (tls_out.active == fd) rc = tls_write(FALSE, block, len); else #endif rc = write(fd, block, len); save_errno = errno; @@ -1046,7 +1046,7 @@ dkim_transport_write_message(address_item *addr, int fd, int options, int siglen = Ustrlen(dkim_signature); while(siglen > 0) { #ifdef SUPPORT_TLS - if (tls_active == fd) wwritten = tls_write(dkim_signature, siglen); else + if (tls_out.active == fd) wwritten = tls_write(FALSE, dkim_signature, siglen); else #endif wwritten = write(fd,dkim_signature,siglen); if (wwritten == -1) { @@ -1072,7 +1072,7 @@ dkim_transport_write_message(address_item *addr, int fd, int options, to the socket. However only if we don't use TLS, in which case theres another layer of indirection before the data finally hits the socket. */ - if (tls_active != fd) + if (tls_out.active != fd) { ssize_t copied = 0; off_t offset = 0; @@ -1096,7 +1096,7 @@ dkim_transport_write_message(address_item *addr, int fd, int options, /* write the chunk */ DKIM_WRITE: #ifdef SUPPORT_TLS - if (tls_active == fd) wwritten = tls_write(US p, sread); else + if (tls_out.active == fd) wwritten = tls_write(FALSE, US p, sread); else #endif wwritten = write(fd,p,sread); if (wwritten == -1) @@ -1226,9 +1226,14 @@ if ((write_pid = fork()) == 0) size_limit, add_headers, remove_headers, NULL, NULL, rewrite_rules, rewrite_existflags); save_errno = errno; - (void)write(pfd[pipe_write], (void *)&rc, sizeof(BOOL)); - (void)write(pfd[pipe_write], (void *)&save_errno, sizeof(int)); - (void)write(pfd[pipe_write], (void *)&(addr->more_errno), sizeof(int)); + if ( write(pfd[pipe_write], (void *)&rc, sizeof(BOOL)) + != sizeof(BOOL) + || write(pfd[pipe_write], (void *)&save_errno, sizeof(int)) + != sizeof(int) + || write(pfd[pipe_write], (void *)&(addr->more_errno), sizeof(int)) + != sizeof(int) + ) + rc = FALSE; /* compiler quietening */ _exit(0); } save_errno = errno; @@ -1339,11 +1344,11 @@ if (write_pid > 0) if (rc == 0) { BOOL ok; - (void)read(pfd[pipe_read], (void *)&ok, sizeof(BOOL)); + int dummy = read(pfd[pipe_read], (void *)&ok, sizeof(BOOL)); if (!ok) { - (void)read(pfd[pipe_read], (void *)&save_errno, sizeof(int)); - (void)read(pfd[pipe_read], (void *)&(addr->more_errno), sizeof(int)); + dummy = read(pfd[pipe_read], (void *)&save_errno, sizeof(int)); + dummy = read(pfd[pipe_read], (void *)&(addr->more_errno), sizeof(int)); yield = FALSE; } } @@ -1992,7 +1997,122 @@ if (expand_arguments) memmove(argv + i + 1 + additional, argv + i + 1, (argcount - i)*sizeof(uschar *)); - for (ad = addr; ad != NULL; ad = ad->next) argv[i++] = ad->address; + for (ad = addr; ad != NULL; ad = ad->next) { + argv[i++] = ad->address; + argcount++; + } + + /* Subtract one since we replace $pipe_addresses */ + argcount--; + i--; + } + + /* Handle special case of $address_pipe when af_force_command is set */ + + else if (addr != NULL && testflag(addr,af_force_command) && + (Ustrcmp(argv[i], "$address_pipe") == 0 || + Ustrcmp(argv[i], "${address_pipe}") == 0)) + { + int address_pipe_i; + int address_pipe_argcount = 0; + int address_pipe_max_args; + uschar **address_pipe_argv; + + /* We can never have more then the argv we will be loading into */ + address_pipe_max_args = max_args - argcount + 1; + + DEBUG(D_transport) + debug_printf("address_pipe_max_args=%d\n", address_pipe_max_args); + + /* We allocate an additional for (uschar *)0 */ + address_pipe_argv = store_get((address_pipe_max_args+1)*sizeof(uschar *)); + + /* +1 because addr->local_part[0] == '|' since af_force_command is set */ + s = expand_string(addr->local_part + 1); + + if (s == NULL || *s == '\0') + { + addr->transport_return = FAIL; + addr->message = string_sprintf("Expansion of \"%s\" " + "from command \"%s\" in %s failed: %s", + (addr->local_part + 1), cmd, etext, expand_string_message); + return FALSE; + } + + while (isspace(*s)) s++; /* strip leading space */ + + while (*s != 0 && address_pipe_argcount < address_pipe_max_args) + { + if (*s == '\'') + { + ss = s + 1; + while (*ss != 0 && *ss != '\'') ss++; + address_pipe_argv[address_pipe_argcount++] = ss = store_get(ss - s++); + while (*s != 0 && *s != '\'') *ss++ = *s++; + if (*s != 0) s++; + *ss++ = 0; + } + else address_pipe_argv[address_pipe_argcount++] = string_dequote(&s); + while (isspace(*s)) s++; /* strip space after arg */ + } + + address_pipe_argv[address_pipe_argcount] = (uschar *)0; + + /* If *s != 0 we have run out of argument slots. */ + if (*s != 0) + { + uschar *msg = string_sprintf("Too many arguments in $address_pipe " + "\"%s\" in %s", addr->local_part + 1, etext); + if (addr != NULL) + { + addr->transport_return = FAIL; + addr->message = msg; + } + else *errptr = msg; + return FALSE; + } + + /* address_pipe_argcount - 1 + * because we are replacing $address_pipe in the argument list + * with the first thing it expands to */ + if (argcount + address_pipe_argcount - 1 > max_args) + { + addr->transport_return = FAIL; + addr->message = string_sprintf("Too many arguments to command " + "\"%s\" after expanding $address_pipe in %s", cmd, etext); + return FALSE; + } + + /* If we are not just able to replace the slot that contained + * $address_pipe (address_pipe_argcount == 1) + * We have to move the existing argv by address_pipe_argcount - 1 + * Visually if address_pipe_argcount == 2: + * [argv 0][argv 1][argv 2($address_pipe)][argv 3][0] + * [argv 0][argv 1][ap_arg0][ap_arg1][old argv 3][0] + */ + if (address_pipe_argcount > 1) + memmove( + /* current position + additonal args */ + argv + i + address_pipe_argcount, + /* current position + 1 (for the (uschar *)0 at the end) */ + argv + i + 1, + /* -1 for the (uschar *)0 at the end)*/ + (argcount - i)*sizeof(uschar *) + ); + + /* Now we fill in the slots we just moved argv out of + * [argv 0][argv 1][argv 2=pipeargv[0]][argv 3=pipeargv[1]][old argv 3][0] + */ + for (address_pipe_i = 0; + address_pipe_argv[address_pipe_i] != (uschar *)0; + address_pipe_i++) + { + argv[i++] = address_pipe_argv[address_pipe_i]; + argcount++; + } + + /* Subtract one since we replace $address_pipe */ + argcount--; i--; }