X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/568092148bf6ade68174fa1ccf34b8c37d9064e9..cf39dad3d551222a3e1f681995c287eb53e2596f:/src/src/transport.c diff --git a/src/src/transport.c b/src/src/transport.c index e5a7385b4..49a84ccc4 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -3,6 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ /* General functions concerned with transportation, and generic options for all @@ -885,7 +886,7 @@ transport_write_timeout non-zero. Arguments: tctx - (fd, msg) Either and fd, to write the message to, + (fd, msg) Either an fd, to write the message to, or a string: if null write message to allocated space otherwire take content as headers. addr (chain of) addresses (for extra headers), or NULL; @@ -904,6 +905,7 @@ Arguments: add_delivery_date if TRUE, add a "delivery-date" header use_crlf if TRUE, turn NL into CR LF end_dot if TRUE, send a terminating "." line at the end + no_flush if TRUE, do not flush at end no_headers if TRUE, omit the headers no_body if TRUE, omit the body check_string a string to check for at the start of lines, or NULL @@ -1160,8 +1162,9 @@ if (tctx->options & topt_end_dot && !write_chunk(tctx, US".\n", 2)) /* Write out any remaining data in the buffer before returning. */ -return (len = chunk_ptr - deliver_out_buffer) <= 0 || - transport_write_block(tctx, deliver_out_buffer, len, FALSE); +return (len = chunk_ptr - deliver_out_buffer) <= 0 + || transport_write_block(tctx, deliver_out_buffer, len, + !!(tctx->options & topt_no_flush)); } @@ -1234,10 +1237,10 @@ write_pid = (pid_t)(-1); { int bits = fcntl(tctx->u.fd, F_GETFD); - (void)fcntl(tctx->u.fd, F_SETFD, bits | FD_CLOEXEC); + (void) fcntl(tctx->u.fd, F_SETFD, bits | FD_CLOEXEC); filter_pid = child_open(USS transport_filter_argv, NULL, 077, - &fd_write, &fd_read, FALSE); - (void)fcntl(tctx->u.fd, F_SETFD, bits & ~FD_CLOEXEC); + &fd_write, &fd_read, FALSE, US"transport-filter"); + (void) fcntl(tctx->u.fd, F_SETFD, bits & ~FD_CLOEXEC); } if (filter_pid < 0) goto TIDY_UP; /* errno set */ @@ -1250,7 +1253,7 @@ via a(nother) pipe. While writing to the filter, we do not do the CRLF, smtp dots, or check string processing. */ if (pipe(pfd) != 0) goto TIDY_UP; /* errno set */ -if ((write_pid = exim_fork(US"transport filter writer")) == 0) +if ((write_pid = exim_fork(US"tpt-filter-writer")) == 0) { BOOL rc; (void)close(fd_read); @@ -1259,7 +1262,7 @@ if ((write_pid = exim_fork(US"transport filter writer")) == 0) tctx->u.fd = fd_write; tctx->check_string = tctx->escape_string = NULL; - tctx->options &= ~(topt_use_crlf | topt_end_dot | topt_use_bdat); + tctx->options &= ~(topt_use_crlf | topt_end_dot | topt_use_bdat | topt_no_flush); rc = internal_transport_write_message(tctx, size_limit); @@ -1274,7 +1277,7 @@ if ((write_pid = exim_fork(US"transport filter writer")) == 0) != sizeof(struct timeval) ) rc = FALSE; /* compiler quietening */ - exim_underbar_exit(0, US"tpt-filter writer"); + exim_underbar_exit(EXIT_SUCCESS); } save_errno = errno; @@ -1399,7 +1402,6 @@ if (write_pid > 0) 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->delivery_time, sizeof(struct timeval)); - dummy = dummy; /* compiler quietening */ yield = FALSE; } } @@ -1570,7 +1572,7 @@ for (host_item * host = hostlist; host; host = host->next) { sprintf(CS buffer, "%.200s:%d", host->name, host_record->sequence); dbfn_write(dbm_file, buffer, host_record, sizeof(dbdata_wait) + host_length); -#ifdef EXPERIMENTAL_QUEUE_RAMP +#ifndef DISABLE_QUEUE_RAMP if (f.queue_2stage && queue_fast_ramp && !queue_run_in_order) queue_notify_daemon(message_id); #endif @@ -1599,7 +1601,8 @@ for (host_item * host = hostlist; host; host = host->next) /* Update the database */ dbfn_write(dbm_file, host->name, host_record, sizeof(dbdata_wait) + host_length); - DEBUG(D_transport) debug_printf("added to list for %s\n", host->name); + DEBUG(D_transport) debug_printf("added %.*s to queue for %s\n", + MESSAGE_ID_LENGTH, message_id, host->name); } /* All now done */ @@ -1627,7 +1630,6 @@ Arguments: local_message_max maximum number of messages down one connection as set by the caller transport new_message_id set to the message id of a waiting message - more set TRUE if there are yet more messages waiting oicf_func function to call to validate if it is ok to send to this message_id from the current instance. oicf_data opaque data for oicf_func @@ -1643,7 +1645,7 @@ typedef struct msgq_s BOOL transport_check_waiting(const uschar *transport_name, const uschar *hostname, - int local_message_max, uschar *new_message_id, BOOL *more, oicf oicf_func, void *oicf_data) + int local_message_max, uschar *new_message_id, oicf oicf_func, void *oicf_data) { dbdata_wait *host_record; int host_length; @@ -1653,13 +1655,12 @@ open_db *dbm_file; int i; struct stat statbuf; -*more = FALSE; - DEBUG(D_transport) { debug_printf("transport_check_waiting entered\n"); debug_printf(" sequence=%d local_max=%d global_max=%d\n", continue_sequence, local_message_max, connection_max_messages); + acl_level++; } /* Do nothing if we have hit the maximum number that can be send down one @@ -1669,23 +1670,23 @@ if (connection_max_messages >= 0) local_message_max = connection_max_messages; if (local_message_max > 0 && continue_sequence >= local_message_max) { DEBUG(D_transport) - debug_printf("max messages for one connection reached: returning\n"); - return FALSE; + debug_printf_indent("max messages for one connection reached: returning\n"); + goto retfalse; } /* Open the waiting information database. */ if (!(dbm_file = dbfn_open(string_sprintf("wait-%.200s", transport_name), O_RDWR, &dbblock, TRUE, TRUE))) - return FALSE; + goto retfalse; /* See if there is a record for this host; if not, there's nothing to do. */ if (!(host_record = dbfn_read(dbm_file, hostname))) { dbfn_close(dbm_file); - DEBUG(D_transport) debug_printf("no messages waiting for %s\n", hostname); - return FALSE; + DEBUG(D_transport) debug_printf_indent("no messages waiting for %s\n", hostname); + goto retfalse; } /* If the data in the record looks corrupt, just log something and @@ -1696,7 +1697,7 @@ if (host_record->count > WAIT_NAME_MAX) dbfn_close(dbm_file); log_write(0, LOG_MAIN|LOG_PANIC, "smtp-wait database entry for %s has bad " "count=%d (max=%d)", hostname, host_record->count, WAIT_NAME_MAX); - return FALSE; + goto retfalse; } /* Scan the message ids in the record from the end towards the beginning, @@ -1834,8 +1835,8 @@ while (1) if (host_length <= 0) { dbfn_close(dbm_file); - DEBUG(D_transport) debug_printf("waiting messages already delivered\n"); - return FALSE; + DEBUG(D_transport) debug_printf_indent("waiting messages already delivered\n"); + goto retfalse; } /* we were not able to find an acceptable message, nor was there a @@ -1846,7 +1847,7 @@ while (1) { Ustrcpy(new_message_id, message_id); dbfn_close(dbm_file); - return FALSE; + goto retfalse; } } /* we need to process a continuation record */ @@ -1858,13 +1859,16 @@ record if required, close the database, and return TRUE. */ if (host_length > 0) { host_record->count = host_length/MESSAGE_ID_LENGTH; - dbfn_write(dbm_file, hostname, host_record, (int)sizeof(dbdata_wait) + host_length); - *more = TRUE; } dbfn_close(dbm_file); +DEBUG(D_transport) {acl_level--; debug_printf("transport_check_waiting: TRUE\n"); } return TRUE; + +retfalse: +DEBUG(D_transport) {acl_level--; debug_printf("transport_check_waiting: FALSE\n"); } +return FALSE; } /************************************************* @@ -1876,7 +1880,7 @@ void transport_do_pass_socket(const uschar *transport_name, const uschar *hostname, const uschar *hostaddress, uschar *id, int socket_fd) { -int i = 20; +int i = 27; const uschar **argv; /* Set up the calling arguments; use the standard function for the basics, @@ -1897,6 +1901,16 @@ if (smtp_peer_options & OPTION_TLS) argv[i++] = sending_ip_address; argv[i++] = string_sprintf("%d", sending_port); argv[i++] = tls_out.active.sock >= 0 ? tls_out.cipher : continue_proxy_cipher; + + if (tls_out.sni) + { + argv[i++] = +#ifdef SUPPORT_DANE + tls_out.dane_verified ? US"-MCr" : +#endif + US"-MCs"; + argv[i++] = tls_out.sni; + } } else argv[i++] = US"-MCT"; @@ -1909,6 +1923,17 @@ if (queue_run_pid != (pid_t)0) argv[i++] = string_sprintf("%d", queue_run_pipe); } +#ifdef SUPPORT_SOCKS +if (proxy_session) + { + argv[i++] = US"-MCp"; + argv[i++] = proxy_local_address; + argv[i++] = string_sprintf("%d", proxy_local_port); + argv[i++] = proxy_external_address; + argv[i++] = string_sprintf("%d", proxy_external_port); + } +#endif + argv[i++] = US"-MC"; argv[i++] = US transport_name; argv[i++] = US hostname; @@ -1958,7 +1983,7 @@ int status; DEBUG(D_transport) debug_printf("transport_pass_socket entered\n"); -if ((pid = exim_fork(US"continued-transport interproc")) == 0) +if ((pid = exim_fork(US"continued-transport-interproc")) == 0) { /* Disconnect entirely from the parent process. If we are running in the test harness, wait for a bit to allow the previous process time to finish, @@ -1966,11 +1991,8 @@ if ((pid = exim_fork(US"continued-transport interproc")) == 0) automatic comparison. */ if ((pid = exim_fork(US"continued-transport")) != 0) - { - DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (final-pid %d)\n", pid); _exit(EXIT_SUCCESS); - } - testharness_pause_ms(1000); /*TTT*/ + testharness_pause_ms(1000); transport_do_pass_socket(transport_name, hostname, hostaddress, id, socket_fd); @@ -1984,7 +2006,6 @@ if (pid > 0) { int rc; while ((rc = wait(&status)) != pid && (rc >= 0 || errno != ECHILD)); - DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (inter-pid %d)\n", pid); return TRUE; } else @@ -2226,12 +2247,12 @@ if (expand_arguments) } /* 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] - */ + $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 + additional args */ @@ -2243,15 +2264,12 @@ if (expand_arguments) ); /* 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] - */ + [argv 0][argv 1][argv 2=pipeargv[0]][argv 3=pipeargv[1]][old argv 3][0] */ + for (int address_pipe_i = 0; address_pipe_argv[address_pipe_i] != US 0; - address_pipe_i++) - { + address_pipe_i++, argcount++) argv[i++] = address_pipe_argv[address_pipe_i]; - argcount++; - } /* Subtract one since we replace $address_pipe */ argcount--;