*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
/* A number of functions for driving outgoing SMTP calls. */
return FALSE;
}
-while (isspace(*expint)) expint++;
-if (*expint == 0) return TRUE;
+if (is_tainted(expint))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "attempt to use tainted value '%s' from '%s' for interface",
+ expint, istring);
+ addr->transport_return = PANIC;
+ addr->message = string_sprintf("failed to expand \"interface\" "
+ "option for %s: configuration error", msg);
+ return FALSE;
+ }
+
+Uskip_whitespace(&expint);
+if (!*expint) return TRUE;
while ((iface = string_nextinlist(&expint, &sep, big_buffer,
big_buffer_size)))
static void
tfo_out_check(int sock)
{
-# if defined(TCP_INFO) && defined(EXIM_HAVE_TCPI_UNACKED)
+# ifdef __FreeBSD__
+struct tcp_info tinfo;
+int val;
+socklen_t len = sizeof(val);
+
+/* The observability as of 12.1 is not useful as a client, only telling us that
+a TFO option was used on SYN. It could have been a TFO-R, or ignored by the
+server. */
+
+/*
+if (tcp_out_fastopen == TFO_ATTEMPTED_NODATA || tcp_out_fastopen == TFO_ATTEMPTED_DATA)
+ if (getsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &val, &len) == 0 && val != 0) {}
+*/
+switch (tcp_out_fastopen)
+ {
+ case TFO_ATTEMPTED_NODATA: tcp_out_fastopen = TFO_USED_NODATA; break;
+ case TFO_ATTEMPTED_DATA: tcp_out_fastopen = TFO_USED_DATA; break;
+ default: break; /* compiler quietening */
+ }
+
+# else /* Linux & Apple */
+# if defined(TCP_INFO) && defined(EXIM_HAVE_TCPI_UNACKED)
struct tcp_info tinfo;
socklen_t len = sizeof(tinfo);
default: break; /* compiler quietening */
}
-# endif
+# endif
+# endif /* Linux & Apple */
}
#endif
{
HDEBUG(D_transport|D_acl|D_v)
{
- debug_printf_indent("failed: %s", CUstrerror(save_errno));
+ debug_printf_indent(" failed: %s", CUstrerror(save_errno));
if (save_errno == ETIMEDOUT)
debug_printf(" (timeout=%s)", readconf_printtime(timeout));
debug_printf("\n");
union sockaddr_46 interface_sock;
EXIM_SOCKLEN_T size = sizeof(interface_sock);
- HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("connected\n");
+ HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" connected\n");
if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0)
sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port);
else
rc = n;
}
else
-
+ {
rc = send(outblock->cctx->sock, outblock->buffer, n,
#ifdef MSG_MORE
more ? MSG_MORE : 0
0
#endif
);
+
+#if defined(__linux__)
+ /* This is a workaround for a current linux kernel bug: as of
+ 5.6.8-200.fc31.x86_64 small (<MSS) writes get delayed by about 200ms,
+ This is despite NODELAY being active.
+ https://bugzilla.redhat.com/show_bug.cgi?id=1803806 */
+
+ if (!more)
+ setsockopt(outblock->cctx->sock, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
+#endif
+ }
}
if (rc <= 0)
gstring gs = { .size = big_buffer_size, .ptr = 0, .s = big_buffer };
va_list ap;
+ /* Use taint-unchecked routines for writing into big_buffer, trusting that
+ we'll never expand the results. Actually, the error-message use - leaving
+ the results in big_buffer for potential later use - is uncomfortably distant.
+ XXX Would be better to assume all smtp commands are short, use normal pool
+ alloc rather than big_buffer, and another global for the data-for-error. */
+
va_start(ap, format);
- if (!string_vformat(&gs, FALSE, CS format, ap))
+ if (!string_vformat(&gs, SVFMT_TAINT_NOCHK, CS format, ap))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong write_command in outgoing "
"SMTP");
va_end(ap);
if (!flush_buffer(outblock, SCMD_FLUSH)) return -1;
}
- Ustrncpy(CS outblock->ptr, gs.s, gs.ptr);
+ Ustrncpy(outblock->ptr, gs.s, gs.ptr);
outblock->ptr += gs.ptr;
outblock->cmd_count++;
gs.ptr -= 2; string_from_gstring(&gs); /* remove \r\n for error message */
inblock the SMTP input block (contains holding buffer, socket, etc.)
buffer where to put the line
size space available for the line
- timeout the timeout to use when reading a packet
+ timelimit deadline for reading the lime, seconds past epoch
Returns: length of a line that has been put in the buffer
-1 otherwise, with errno set
*/
static int
-read_response_line(smtp_inblock *inblock, uschar *buffer, int size, int timeout)
+read_response_line(smtp_inblock *inblock, uschar *buffer, int size, time_t timelimit)
{
uschar *p = buffer;
uschar *ptr = inblock->ptr;
/* Need to read a new input packet. */
- if((rc = ip_recv(cctx, inblock->buffer, inblock->buffersize, timeout)) <= 0)
+ if((rc = ip_recv(cctx, inblock->buffer, inblock->buffersize, timelimit)) <= 0)
{
- DEBUG(D_deliver|D_transport|D_acl)
+ DEBUG(D_deliver|D_transport|D_acl|D_v)
debug_printf_indent(errno ? " SMTP(%s)<<\n" : " SMTP(closed)<<\n",
strerror(errno));
break;
smtp_context * sx = sx0;
uschar * ptr = buffer;
int count = 0;
+time_t timelimit = time(NULL) + timeout;
errno = 0; /* Ensure errno starts out zero */
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifndef DISABLE_PIPE_CONNECT
if (sx->pending_BANNER || sx->pending_EHLO)
{
int rc;
for (;;)
{
- if ((count = read_response_line(&sx->inblock, ptr, size, timeout)) < 0)
+ if ((count = read_response_line(&sx->inblock, ptr, size, timelimit)) < 0)
return FALSE;
HDEBUG(D_transport|D_acl|D_v)