X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/ee8b809061baea861fc87c41bcb72a62d76b0047..ff9663026d1a318d385730c4a2c3e85508b4b00b:/src/src/smtp_out.c diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 1209c7fd9..12ed5bc61 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -52,6 +52,17 @@ if (!(expint = expand_string(istring))) return FALSE; } +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; + } + while (isspace(*expint)) expint++; if (*expint == 0) return TRUE; @@ -144,7 +155,28 @@ return TRUE; 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); @@ -191,8 +223,11 @@ switch (tcp_out_fastopen) tcp_out_fastopen = TFO_NOT_USED; } break; + + default: break; /* compiler quietening */ } -# endif +# endif +# endif /* Linux & Apple */ } #endif @@ -294,7 +329,7 @@ if (save_errno != 0) { 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"); @@ -311,7 +346,7 @@ else 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 @@ -442,7 +477,7 @@ BOOL more = mode == SCMD_MORE; HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n, more ? " (more expected)" : ""); -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS if (outblock->cctx->tls_ctx) rc = tls_write(outblock->cctx->tls_ctx, outblock->buffer, n, more); else @@ -465,7 +500,7 @@ else rc = n; } else - + { rc = send(outblock->cctx->sock, outblock->buffer, n, #ifdef MSG_MORE more ? MSG_MORE : 0 @@ -473,6 +508,7 @@ else 0 #endif ); + } } if (rc <= 0) @@ -512,34 +548,40 @@ int smtp_write_command(void * sx, int mode, const char *format, ...) { smtp_outblock * outblock = &((smtp_context *)sx)->outblock; -int count; int rc = 0; -va_list ap; if (format) { + 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(big_buffer, big_buffer_size, 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); - count = Ustrlen(big_buffer); + string_from_gstring(&gs); - if (count > outblock->buffersize) + if (gs.ptr > outblock->buffersize) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong write_command in outgoing " "SMTP"); - if (count > outblock->buffersize - (outblock->ptr - outblock->buffer)) + if (gs.ptr > outblock->buffersize - (outblock->ptr - outblock->buffer)) { rc = outblock->cmd_count; /* flush resets */ if (!flush_buffer(outblock, SCMD_FLUSH)) return -1; } - Ustrncpy(CS outblock->ptr, big_buffer, count); - outblock->ptr += count; + Ustrncpy(outblock->ptr, gs.s, gs.ptr); + outblock->ptr += gs.ptr; outblock->cmd_count++; - count -= 2; - big_buffer[count] = 0; /* remove \r\n for error message */ + gs.ptr -= 2; string_from_gstring(&gs); /* remove \r\n for error message */ /* We want to hide the actual data sent in AUTH transactions from reflections and logs. While authenticating, a flag is set in the outblock to enable this. @@ -587,14 +629,14 @@ Arguments: 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; @@ -637,9 +679,9 @@ for (;;) /* 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; @@ -688,22 +730,28 @@ Returns: TRUE if a valid, non-error response was received; else FALSE /*XXX could move to smtp transport; no other users */ BOOL -smtp_read_response(void * sx0, uschar *buffer, int size, int okdigit, +smtp_read_response(void * sx0, uschar * buffer, int size, int okdigit, int timeout) { smtp_context * sx = sx0; -uschar *ptr = buffer; +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) - if (smtp_reap_early_pipe(sx, &count) != OK) + { + int rc; + if ((rc = smtp_reap_early_pipe(sx, &count)) != OK) { DEBUG(D_transport) debug_printf("failed reaping pipelined cmd responsess\n"); + buffer[0] = '\0'; + if (rc == DEFER) errno = ERRNO_TLSFAILURE; return FALSE; } + } #endif /* This is a loop to read and concatenate the lines that make up a multi-line @@ -711,7 +759,7 @@ response. */ 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)