X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/78a3bbd585b7ee0961dee45163c36904a419388b..6a69d109fb79fb19663137cf606557d663169373:/src/src/verify.c diff --git a/src/src/verify.c b/src/src/verify.c index 794c76c4e..5c093bf31 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -68,9 +68,7 @@ int length, expire; time_t now; dbdata_callout_cache *cache_record; -cache_record = dbfn_read_with_length(dbm_file, key, &length); - -if (cache_record == NULL) +if (!(cache_record = dbfn_read_with_length(dbm_file, key, &length))) { HDEBUG(D_verify) debug_printf("callout cache: no %s record found for %s\n", type, key); return NULL; @@ -408,7 +406,7 @@ if (addr->transport == cutthrough.addr.transport) /* Match! Send the RCPT TO, set done from the response */ done = - smtp_write_command(&ctblock, FALSE, "RCPT TO:<%.1000s>\r\n", + smtp_write_command(&ctblock, SCMD_FLUSH, "RCPT TO:<%.1000s>\r\n", transport_rcpt_address(addr, addr->transport->rcpt_include_affixes)) >= 0 && cutthrough_response(cutthrough.fd, '2', &resp, CUTTHROUGH_DATA_TIMEOUT) == '2'; @@ -785,26 +783,33 @@ tls_retry_connection: postmaster-verify. The sync_responses() would need to be taught about it and we'd need another return code filtering out to here. + + Avoid using a SIZE option on the MAIL for all randon-rcpt checks. */ + sx.avoid_option = OPTION_SIZE; + /* Remember when we last did a random test */ new_domain_record.random_stamp = time(NULL); if (smtp_write_mail_and_rcpt_cmds(&sx, &yield) == 0) switch(addr->transport_return) { - case PENDING_OK: + case PENDING_OK: /* random was accepted, unfortunately */ new_domain_record.random_result = ccache_accept; - break; - case FAIL: + yield = OK; /* Only usable verify result we can return */ + done = TRUE; + goto no_conn; + case FAIL: /* rejected: the preferred result */ new_domain_record.random_result = ccache_reject; + sx.avoid_option = 0; /* Between each check, issue RSET, because some servers accept only one recipient after MAIL FROM:<>. XXX We don't care about that for postmaster_full. Should we? */ if ((done = - smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0 && + smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0 && smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer), '2', callout))) break; @@ -829,6 +834,8 @@ tls_retry_connection: sx.send_rset = TRUE; sx.completed_addr = FALSE; goto tls_retry_connection; + case DEFER: /* 4xx response to random */ + break; /* Just to be clear. ccache_unknown, !done. */ } /* Re-setup for main verify, or for the error message when failing */ @@ -842,12 +849,14 @@ tls_retry_connection: else done = TRUE; - /* Main verify. If the host is accepting all local parts, as determined - by the "random" check, we don't need to waste time doing any further - checking. */ + /* Main verify. For rcpt-verify use SIZE if we know it and we're not cacheing; + for sndr-verify never use it. */ if (done) { + if (!(options & vopt_is_recipient && options & vopt_callout_no_cache)) + sx.avoid_option = OPTION_SIZE; + done = FALSE; switch(smtp_write_mail_and_rcpt_cmds(&sx, &yield)) { @@ -856,12 +865,12 @@ tls_retry_connection: case PENDING_OK: done = TRUE; new_address_record.result = ccache_accept; break; - case FAIL: done = TRUE; + case FAIL: done = TRUE; yield = FAIL; *failure_ptr = US"recipient"; new_address_record.result = ccache_reject; break; - default: break; + default: break; } break; @@ -897,7 +906,7 @@ tls_retry_connection: cancel_cutthrough_connection(TRUE, US"postmaster verify"); HDEBUG(D_acl|D_v) debug_printf_indent("Cutthrough cancelled by presence of postmaster verify\n"); - done = smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0 + done = smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0 && smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer), '2', callout); @@ -914,6 +923,7 @@ tls_retry_connection: sx.ok = FALSE; sx.send_rset = TRUE; sx.completed_addr = FALSE; + sx.avoid_option = OPTION_SIZE; if( smtp_write_mail_and_rcpt_cmds(&sx, &yield) == 0 && addr->transport_return == PENDING_OK @@ -921,7 +931,7 @@ tls_retry_connection: done = TRUE; else done = (options & vopt_callout_fullpm) != 0 - && smtp_write_command(&sx.outblock, FALSE, + && smtp_write_command(&sx.outblock, SCMD_FLUSH, "RCPT TO:\r\n") >= 0 && smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer), '2', callout); @@ -983,7 +993,7 @@ no_conn: if (*sx.buffer == 0) Ustrcpy(sx.buffer, US"connection dropped"); /*XXX test here is ugly; seem to have a split of responsibility for - building this message. Need to reationalise. Where is it done + building this message. Need to rationalise. Where is it done before here, and when not? Not == 5xx resp to MAIL on main-verify */ @@ -1065,7 +1075,7 @@ no_conn: cancel_cutthrough_connection(TRUE, US"not usable for cutthrough"); if (sx.send_quit) { - (void) smtp_write_command(&sx.outblock, FALSE, "QUIT\r\n"); + (void) smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n"); /* Wait a short time for response, and discard it */ smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer), @@ -1177,7 +1187,7 @@ if(cutthrough.fd < 0) if( #ifdef SUPPORT_TLS - (tls_out.active == cutthrough.fd) ? tls_write(FALSE, ctblock.buffer, n) : + tls_out.active == cutthrough.fd ? tls_write(FALSE, ctblock.buffer, n, FALSE) : #endif send(cutthrough.fd, ctblock.buffer, n, 0) > 0 ) @@ -1308,9 +1318,9 @@ return cutthrough_response(cutthrough.fd, '3', NULL, CUTTHROUGH_DATA_TIMEOUT) == } -/* fd and tctx args only to match write_chunk() */ +/* tctx arg only to match write_chunk() */ static BOOL -cutthrough_write_chunk(int fd, transport_ctx * tctx, uschar * s, int len) +cutthrough_write_chunk(transport_ctx * tctx, uschar * s, int len) { uschar * s2; while(s && (s2 = Ustrchr(s, '\n'))) @@ -1339,13 +1349,15 @@ if(cutthrough.fd < 0 || cutthrough.callout_hold_only) */ HDEBUG(D_acl) debug_printf_indent("----------- start cutthrough headers send -----------\n"); +tctx.u.fd = cutthrough.fd; tctx.tblock = cutthrough.addr.transport; tctx.addr = &cutthrough.addr; tctx.check_string = US"."; tctx.escape_string = US".."; +/*XXX check under spool_files_wireformat. Might be irrelevant */ tctx.options = topt_use_crlf; -if (!transport_headers_send(cutthrough.fd, &tctx, &cutthrough_write_chunk)) +if (!transport_headers_send(&tctx, &cutthrough_write_chunk)) return FALSE; HDEBUG(D_acl) debug_printf_indent("----------- done cutthrough headers send ------------\n"); @@ -1394,6 +1406,7 @@ cutthrough.delivery = cutthrough.callout_hold_only = FALSE; void release_cutthrough_connection(const uschar * why) { +if (cutthrough.fd < 0) return; HDEBUG(D_acl) debug_printf_indent("release cutthrough conn: %s\n", why); cutthrough.fd = -1; cutthrough.delivery = cutthrough.callout_hold_only = FALSE; @@ -1514,7 +1527,7 @@ va_list ap; va_start(ap, format); if (smtp_out && (f == smtp_out)) - smtp_vprintf(format, ap); + smtp_vprintf(format, FALSE, ap); else vfprintf(f, format, ap); va_end(ap); @@ -1776,16 +1789,16 @@ while (addr_new) transport. */ transport_feedback tf = { - NULL, /* interface (=> any) */ - US"smtp", /* port */ - US"smtp", /* protocol */ - NULL, /* hosts */ - US"$smtp_active_hostname", /* helo_data */ - FALSE, /* hosts_override */ - FALSE, /* hosts_randomize */ - FALSE, /* gethostbyname */ - TRUE, /* qualify_single */ - FALSE /* search_parents */ + .interface = NULL, /* interface (=> any) */ + .port = US"smtp", + .protocol = US"smtp", + .hosts = NULL, + .helo_data = US"$smtp_active_hostname", + .hosts_override = FALSE, + .hosts_randomize = FALSE, + .gethostbyname = FALSE, + .qualify_single = TRUE, + .search_parents = FALSE }; /* If verification yielded a remote transport, we want to use that @@ -2669,8 +2682,11 @@ if (ip_bind(sock, host_af, interface_address, 0) < 0) goto END_OFF; } +/*XXX could take advantage of TFO early-data. Hmm, what are the +error returns; can we differentiate connect from data fails? +Do we need to? */ if (ip_connect(sock, host_af, sender_host_address, port, - rfc1413_query_timeout, TRUE) < 0) + rfc1413_query_timeout, &tcp_fastopen_nodata) < 0) { if (errno == ETIMEDOUT && LOGGING(ident_timeout)) log_write(0, LOG_MAIN, "ident connection to %s timed out", @@ -2686,10 +2702,24 @@ if (ip_connect(sock, host_af, sender_host_address, port, sprintf(CS buffer, "%d , %d\r\n", sender_host_port, interface_port); qlen = Ustrlen(buffer); if (send(sock, buffer, qlen, 0) < 0) - { - DEBUG(D_ident) debug_printf("ident send failed: %s\n", strerror(errno)); - goto END_OFF; - } + if (errno == ENOTCONN) /* seen for TFO on FreeBSD */ + { + struct timeval tv = { .tv_sec = 0, .tv_usec = 500*1000 }; + fd_set s; + + FD_ZERO(&s); FD_SET(sock, &s); + (void) select(sock+1, NULL, (SELECT_ARG2_TYPE *)&s, (SELECT_ARG2_TYPE *)&s, &tv); + if (send(sock, buffer, qlen, 0) < 0) + { + DEBUG(D_ident) debug_printf("ident re-send failed: %s\n", strerror(errno)); + goto END_OFF; + } + } + else + { + DEBUG(D_ident) debug_printf("ident send failed: %s\n", strerror(errno)); + goto END_OFF; + } /* Read a response line. We put it into the rest of the buffer, using several recv() calls if necessary. */ @@ -3141,18 +3171,16 @@ verify_check_this_host(const uschar **listptr, unsigned int *cache_bits, int rc; unsigned int *local_cache_bits = cache_bits; const uschar *save_host_address = deliver_host_address; -check_host_block cb; -cb.host_name = host_name; -cb.host_address = host_address; +check_host_block cb = { .host_name = host_name, .host_address = host_address }; -if (valueptr != NULL) *valueptr = NULL; +if (valueptr) *valueptr = NULL; /* If the host address starts off ::ffff: it is an IPv6 address in IPv4-compatible mode. Find the IPv4 part for checking against IPv4 addresses. */ -cb.host_ipv4 = (Ustrncmp(host_address, "::ffff:", 7) == 0)? - host_address + 7 : host_address; +cb.host_ipv4 = Ustrncmp(host_address, "::ffff:", 7) == 0 + ? host_address + 7 : host_address; /* During the running of the check, put the IP address into $host_address. In the case of calls from the smtp transport, it will already be there. However,