X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/d185889f47b9b27088e777f7d382295c51271586..d12746bc15d83ab821be36975da0179672708bc1:/src/src/transport.c diff --git a/src/src/transport.c b/src/src/transport.c index 49ea29e0a..8ccdd0389 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 - 2016 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* General functions concerned with transportation, and generic options for all @@ -17,6 +17,7 @@ are other options living inside this structure which can be set only from certain transports. */ optionlist optionlist_transports[] = { + /* name type value */ { "*expand_group", opt_stringptr|opt_hidden|opt_public, (void *)offsetof(transport_instance, expand_gid) }, { "*expand_user", opt_stringptr|opt_hidden|opt_public, @@ -101,7 +102,7 @@ options_from_list(optionlist_transports, nelem(optionlist_transports), US"TRANSP for (ti = transports_available; ti->driver_name[0]; ti++) { - snprintf(buf, sizeof(buf), "_DRIVER_TRANSPORT_%T", ti->driver_name); + spf(buf, sizeof(buf), US"_DRIVER_TRANSPORT_%T", ti->driver_name); builtin_macro_create(buf); options_from_list(ti->options, (unsigned)*ti->options_count, US"TRANSPORT", ti->driver_name); } @@ -241,10 +242,11 @@ for (i = 0; i < 100; i++) { rc = #ifdef SUPPORT_TLS - tls_out.active == fd ? tls_write(FALSE, block, len, more) : + tls_out.active.sock == fd ? tls_write(tls_out.active.tls_ctx, block, len, more) : #endif #ifdef MSG_MORE - more ? send(fd, block, len, MSG_MORE) : + more && !(tctx->options & topt_not_socket) + ? send(fd, block, len, MSG_MORE) : #endif write(fd, block, len); save_errno = errno; @@ -254,19 +256,20 @@ for (i = 0; i < 100; i++) else { - alarm(local_timeout); + ALARM(local_timeout); rc = #ifdef SUPPORT_TLS - tls_out.active == fd ? tls_write(FALSE, block, len, more) : + tls_out.active.sock == fd ? tls_write(tls_out.active.tls_ctx, block, len, more) : #endif #ifdef MSG_MORE - more ? send(fd, block, len, MSG_MORE) : + more && !(tctx->options & topt_not_socket) + ? send(fd, block, len, MSG_MORE) : #endif write(fd, block, len); save_errno = errno; - local_timeout = alarm(0); + local_timeout = ALARM_CLR(0); if (sigalrm_seen) { errno = ETIMEDOUT; @@ -345,12 +348,9 @@ if (!(tctx->options & topt_output_string)) /* Write to expanding-string. NOTE: not NUL-terminated */ if (!tctx->u.msg) - { - tctx->u.msg = store_get(tctx->msg_size = 1024); - tctx->msg_ptr = 0; - } + tctx->u.msg = string_get(1024); -tctx->u.msg = string_catn(tctx->u.msg, &tctx->msg_size, &tctx->msg_ptr, block, len); +tctx->u.msg = string_catn(tctx->u.msg, block, len); return TRUE; } @@ -374,14 +374,16 @@ Returns: the yield of transport_write_block() BOOL transport_write_string(int fd, const char *format, ...) { -transport_ctx tctx = {0}; +transport_ctx tctx = {{0}}; +gstring gs = { .size = big_buffer_size, .ptr = 0, .s = big_buffer }; va_list ap; + va_start(ap, format); -if (!string_vformat(big_buffer, big_buffer_size, format, ap)) +if (!string_vformat(&gs, FALSE, format, ap)) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong formatted string in transport"); va_end(ap); tctx.u.fd = fd; -return transport_write_block(&tctx, big_buffer, Ustrlen(big_buffer), FALSE); +return transport_write_block(&tctx, gs.s, gs.ptr, FALSE); } @@ -495,7 +497,7 @@ for (ptr = start; ptr < end; ptr++) if ( *ptr == '\r' && ptr[1] == '\n' && !(tctx->options & topt_use_crlf) - && spool_file_wireformat + && f.spool_file_wireformat ) ptr++; @@ -505,7 +507,7 @@ for (ptr = start; ptr < end; ptr++) /* Insert CR before NL if required */ - if (tctx->options & topt_use_crlf && !spool_file_wireformat) + if (tctx->options & topt_use_crlf && !f.spool_file_wireformat) *chunk_ptr++ = '\r'; *chunk_ptr++ = '\n'; transport_newlines++; @@ -590,7 +592,7 @@ at = Ustrrchr(addr->address, '@'); plen = (addr->prefix == NULL)? 0 : Ustrlen(addr->prefix); slen = Ustrlen(addr->suffix); -return string_sprintf("%.*s@%s", (at - addr->address - plen - slen), +return string_sprintf("%.*s@%s", (int)(at - addr->address - plen - slen), addr->address + plen, at + 1); } @@ -723,7 +725,7 @@ for (h = header_list; h; h = h->next) if (h->type != htype_old) int len; if (i == 0) - if (!(s = expand_string(s)) && !expand_string_forcedfail) + if (!(s = expand_string(s)) && !f.expand_string_forcedfail) { errno = ERRNO_CHHEADER_FAIL; return FALSE; @@ -829,7 +831,7 @@ if (tblock && (list = CUS tblock->add_headers)) } } } - else if (!expand_string_forcedfail) + else if (!f.expand_string_forcedfail) { errno = ERRNO_CHHEADER_FAIL; return FALSE; } } @@ -934,8 +936,8 @@ so temporarily hide the global that adjusts for its format. */ if (!(tctx->options & topt_no_headers)) { - BOOL save_wireformat = spool_file_wireformat; - spool_file_wireformat = FALSE; + BOOL save_wireformat = f.spool_file_wireformat; + f.spool_file_wireformat = FALSE; /* Add return-path: if requested. */ @@ -992,11 +994,11 @@ if (!(tctx->options & topt_no_headers)) if (!transport_headers_send(tctx, &write_chunk)) { bad: - spool_file_wireformat = save_wireformat; + f.spool_file_wireformat = save_wireformat; return FALSE; } - spool_file_wireformat = save_wireformat; + f.spool_file_wireformat = save_wireformat; } /* When doing RFC3030 CHUNKING output, work out how much data would be in a @@ -1025,7 +1027,7 @@ if (tctx->options & topt_use_bdat) if (size_limit > 0 && fsize > size_limit) fsize = size_limit; size = hsize + fsize; - if (tctx->options & topt_use_crlf && !spool_file_wireformat) + if (tctx->options & topt_use_crlf && !f.spool_file_wireformat) size += body_linecount; /* account for CRLF-expansion */ /* With topt_use_bdat we never do dot-stuffing; no need to @@ -1072,10 +1074,10 @@ This should get used for CHUNKING output and also for writing the -K file for dkim signing, when we had CHUNKING input. */ #ifdef OS_SENDFILE -if ( spool_file_wireformat +if ( f.spool_file_wireformat && !(tctx->options & (topt_no_body | topt_end_dot)) && !nl_check_length - && tls_out.active != tctx->u.fd + && tls_out.active.sock != tctx->u.fd ) { ssize_t copied = 0; @@ -1106,7 +1108,7 @@ DEBUG(D_transport) debug_printf("cannot use sendfile for body: no support\n"); DEBUG(D_transport) if (!(tctx->options & topt_no_body)) debug_printf("cannot use sendfile for body: %s\n", - !spool_file_wireformat ? "spoolfile not wireformat" + !f.spool_file_wireformat ? "spoolfile not wireformat" : tctx->options & topt_end_dot ? "terminating dot wanted" : nl_check_length ? "dot- or From-stuffing wanted" : "TLS output wanted"); @@ -1132,9 +1134,10 @@ if (!(tctx->options & topt_no_body)) if (len != 0) return FALSE; } -/* Finished with the check string */ +/* Finished with the check string, and spool-format consideration */ nl_check_length = nl_escape_length = 0; +f.spool_file_wireformat = FALSE; /* If requested, add a terminating "." line (SMTP output). */ @@ -1171,13 +1174,12 @@ BOOL transport_write_message(transport_ctx * tctx, int size_limit) { BOOL last_filter_was_NL = TRUE; -BOOL save_spool_file_wireformat = spool_file_wireformat; +BOOL save_spool_file_wireformat = f.spool_file_wireformat; int rc, len, yield, fd_read, fd_write, save_errno; int pfd[2] = {-1, -1}; pid_t filter_pid, write_pid; -static transport_ctx dummy_tctx = {0}; -transport_filter_timed_out = FALSE; +f.transport_filter_timed_out = FALSE; /* If there is no filter command set up, call the internal function that does the actual work, passing it the incoming fd, and return its result. */ @@ -1253,6 +1255,8 @@ if ((write_pid = fork()) == 0) != sizeof(int) || write(pfd[pipe_write], (void *)&tctx->addr->more_errno, sizeof(int)) != sizeof(int) + || write(pfd[pipe_write], (void *)&tctx->addr->delivery_usec, sizeof(int)) + != sizeof(int) ) rc = FALSE; /* compiler quietening */ _exit(0); @@ -1275,7 +1279,7 @@ if (write_pid < 0) /* When testing, let the subprocess get going */ -if (running_in_test_harness) millisleep(250); +if (f.running_in_test_harness) millisleep(250); DEBUG(D_transport) debug_printf("process %d writing to transport filter\n", (int)write_pid); @@ -1292,19 +1296,19 @@ no data is returned, that counts as "ended with NL" (default setting of the variable is TRUE). The output should always be unix-format as we converted any wireformat source on writing input to the filter. */ -spool_file_wireformat = FALSE; +f.spool_file_wireformat = FALSE; chunk_ptr = deliver_out_buffer; for (;;) { sigalrm_seen = FALSE; - alarm(transport_filter_timeout); + ALARM(transport_filter_timeout); len = read(fd_read, deliver_in_buffer, DELIVER_IN_BUFFER_SIZE); - alarm(0); + ALARM_CLR(0); if (sigalrm_seen) { errno = ETIMEDOUT; - transport_filter_timed_out = TRUE; + f.transport_filter_timed_out = TRUE; goto TIDY_UP; } @@ -1332,7 +1336,7 @@ there has been an error, kill the processes before waiting for them, just to be sure. Also apply a paranoia timeout. */ TIDY_UP: -spool_file_wireformat = save_spool_file_wireformat; +f.spool_file_wireformat = save_spool_file_wireformat; save_errno = errno; (void)close(fd_read); @@ -1377,7 +1381,9 @@ if (write_pid > 0) else if (!ok) { int dummy = read(pfd[pipe_read], (void *)&save_errno, sizeof(int)); - dummy = read(pfd[pipe_read], (void *)&(tctx->addr->more_errno), sizeof(int)); + dummy = read(pfd[pipe_read], (void *)&tctx->addr->more_errno, sizeof(int)); + dummy = read(pfd[pipe_read], (void *)&tctx->addr->delivery_usec, sizeof(int)); + dummy = dummy; /* compiler quietening */ yield = FALSE; } } @@ -1398,6 +1404,7 @@ filter was not NL, insert a NL to make the SMTP protocol work. */ if (yield) { nl_check_length = nl_escape_length = 0; + f.spool_file_wireformat = FALSE; if ( tctx->options & topt_end_dot && ( last_filter_was_NL ? !write_chunk(tctx, US".\n", 2) @@ -1865,19 +1872,19 @@ but we have a number of extras that may be added. */ argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0); -if (smtp_authenticated) argv[i++] = US"-MCA"; -if (smtp_peer_options & PEER_OFFERED_CHUNKING) argv[i++] = US"-MCK"; -if (smtp_peer_options & PEER_OFFERED_DSN) argv[i++] = US"-MCD"; -if (smtp_peer_options & PEER_OFFERED_PIPE) argv[i++] = US"-MCP"; -if (smtp_peer_options & PEER_OFFERED_SIZE) argv[i++] = US"-MCS"; +if (f.smtp_authenticated) argv[i++] = US"-MCA"; +if (smtp_peer_options & OPTION_CHUNKING) argv[i++] = US"-MCK"; +if (smtp_peer_options & OPTION_DSN) argv[i++] = US"-MCD"; +if (smtp_peer_options & OPTION_PIPE) argv[i++] = US"-MCP"; +if (smtp_peer_options & OPTION_SIZE) argv[i++] = US"-MCS"; #ifdef SUPPORT_TLS -if (smtp_peer_options & PEER_OFFERED_TLS) - if (tls_out.active >= 0 || continue_proxy_cipher) +if (smtp_peer_options & OPTION_TLS) + if (tls_out.active.sock >= 0 || continue_proxy_cipher) { argv[i++] = US"-MCt"; argv[i++] = sending_ip_address; argv[i++] = string_sprintf("%d", sending_port); - argv[i++] = tls_out.active >= 0 ? tls_out.cipher : continue_proxy_cipher; + argv[i++] = tls_out.active.sock >= 0 ? tls_out.cipher : continue_proxy_cipher; } else argv[i++] = US"-MCT"; @@ -1951,7 +1958,7 @@ if ((pid = fork()) == 0) DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (final-pid %d)\n", pid); _exit(EXIT_SUCCESS); } - if (running_in_test_harness) sleep(1); + if (f.running_in_test_harness) sleep(1); transport_do_pass_socket(transport_name, hostname, hostaddress, id, socket_fd); @@ -2047,7 +2054,7 @@ while (*s != 0 && argcount < max_args) while (isspace(*s)) s++; } -argv[argcount] = (uschar *)0; +argv[argcount] = US 0; /* If *s != 0 we have run out of argument slots. */ @@ -2083,7 +2090,7 @@ $recipients. */ DEBUG(D_transport) { debug_printf("direct command:\n"); - for (i = 0; argv[i] != (uschar *)0; i++) + for (i = 0; argv[i] != US 0; i++) debug_printf(" argv[%d] = %s\n", i, string_printing(argv[i])); } @@ -2093,7 +2100,7 @@ if (expand_arguments) addr->parent != NULL && Ustrcmp(addr->parent->address, "system-filter") == 0; - for (i = 0; argv[i] != (uschar *)0; i++) + for (i = 0; argv[i] != US 0; i++) { /* Handle special fudge for passing an address list */ @@ -2177,7 +2184,7 @@ if (expand_arguments) while (isspace(*s)) s++; /* strip space after arg */ } - address_pipe_argv[address_pipe_argcount] = (uschar *)0; + address_pipe_argv[address_pipe_argcount] = US 0; /* If *s != 0 we have run out of argument slots. */ if (*s != 0) @@ -2225,7 +2232,7 @@ if (expand_arguments) * [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_argv[address_pipe_i] != US 0; address_pipe_i++) { argv[i++] = address_pipe_argv[address_pipe_i]; @@ -2242,9 +2249,9 @@ if (expand_arguments) else { const uschar *expanded_arg; - enable_dollar_recipients = allow_dollar_recipients; + f.enable_dollar_recipients = allow_dollar_recipients; expanded_arg = expand_cstring(argv[i]); - enable_dollar_recipients = FALSE; + f.enable_dollar_recipients = FALSE; if (expanded_arg == NULL) { @@ -2266,7 +2273,7 @@ if (expand_arguments) DEBUG(D_transport) { debug_printf("direct command after expansion:\n"); - for (i = 0; argv[i] != (uschar *)0; i++) + for (i = 0; argv[i] != US 0; i++) debug_printf(" argv[%d] = %s\n", i, string_printing(argv[i])); } }