* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2014 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions concerned with verifying things. The original code for callout
{
HDEBUG(D_verify) debug_printf("cannot callout via null transport\n");
}
+else if (Ustrcmp(addr->transport->driver_name, "smtp") != 0)
+ log_write(0, LOG_MAIN|LOG_PANIC|LOG_CONFIG_FOR, "callout transport '%s': %s is non-smtp",
+ addr->transport->name, addr->transport->driver_name);
else
{
smtp_transport_options_block *ob =
- (smtp_transport_options_block *)(addr->transport->options_block);
+ (smtp_transport_options_block *)addr->transport->options_block;
/* The information wasn't available in the cache, so we have to do a real
callout and save the result in the cache for next time, unless no_cache is set,
#endif
if (!(done= smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), '2', callout)))
goto RESPONSE_FAILED;
-
+
/* Not worth checking greeting line for ESMTP support */
if (!(esmtp = verify_check_this_host(&(ob->hosts_avoid_esmtp), NULL,
host->name, host->address, NULL) != OK))
#ifdef SUPPORT_TLS
if (tls_offered &&
verify_check_this_host(&(ob->hosts_avoid_tls), NULL, host->name,
- host->address, NULL) != OK)
+ host->address, NULL) != OK &&
+ verify_check_this_host(&(ob->hosts_verify_avoid_tls), NULL, host->name,
+ host->address, NULL) != OK
+ )
{
uschar buffer2[4096];
if ( !smtps
/* STARTTLS accepted or ssl-on-connect: try to negotiate a TLS session. */
else
{
- int rc = tls_client_start(inblock.sock, host, addr,
- NULL, /* No DH param */
- ob->tls_certificate, ob->tls_privatekey,
- ob->tls_sni,
- ob->tls_verify_certificates, ob->tls_crl,
- ob->tls_require_ciphers, ob->tls_dh_min_bits,
- callout);
+ int oldtimeout = ob->command_timeout;
+ int rc;
+
+ ob->command_timeout = callout;
+ rc = tls_client_start(inblock.sock, host, addr, ob);
+ ob->command_timeout = oldtimeout;
/* TLS negotiation failed; give an error. Try in clear on a new connection,
if the options permit it for this host. */
done = TRUE; /* so far so good; have response to HELO */
- /*XXX the EHLO response would be analyzed here for IGNOREQUOTA, SIZE, PIPELINING, AUTH */
- /* If we haven't authenticated, but are required to, give up. */
+ /*XXX the EHLO response would be analyzed here for IGNOREQUOTA, SIZE, PIPELINING */
- /*XXX "filter command specified for this transport" ??? */
- /* for now, transport_filter by cutthrough-delivery is not supported */
+ /* For now, transport_filter by cutthrough-delivery is not supported */
/* Need proper integration with the proper transport mechanism. */
-
+ if (cutthrough_delivery)
+ {
+ if (addr->transport->filter_command)
+ {
+ cutthrough_delivery= FALSE;
+ HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of transport filter\n");
+ }
+ #ifndef DISABLE_DKIM
+ if (ob->dkim_domain)
+ {
+ cutthrough_delivery= FALSE;
+ HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of DKIM signing\n");
+ }
+ #endif
+ }
SEND_FAILED:
RESPONSE_FAILED:
}
}
+ /* If we haven't authenticated, but are required to, give up. */
+ /* Try to AUTH */
+
+ else done = smtp_auth(responsebuffer, sizeof(responsebuffer),
+ addr, host, ob, esmtp, &inblock, &outblock) == OK &&
+
+ /* Copy AUTH info for logging */
+ ( (addr->authenticator = client_authenticator),
+ (addr->auth_id = client_authenticated_id),
+
+ /* Build a mail-AUTH string (re-using responsebuffer for convenience */
+ !smtp_mail_auth_str(responsebuffer, sizeof(responsebuffer), addr, ob)
+ ) &&
+
+ ( (addr->auth_sndr = client_authenticated_sender),
+
/* Send the MAIL command */
+ (smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>%s\r\n",
+ from_address, responsebuffer) >= 0)
+ ) &&
- else done =
- smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>\r\n",
- from_address) >= 0 &&
smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
'2', callout);
{
cutthrough_fd= outblock.sock; /* We assume no buffer in use in the outblock */
cutthrough_addr = *addr; /* Save the address_item for later logging */
+ cutthrough_addr.next = NULL;
cutthrough_addr.host_used = store_get(sizeof(host_item));
cutthrough_addr.host_used->name = host->name;
cutthrough_addr.host_used->address = host->address;
}
+/* fd and use_crlf args only to match write_chunk() */
+static BOOL
+cutthrough_write_chunk(int fd, uschar * s, int len, BOOL use_crlf)
+{
+uschar * s2;
+while(s && (s2 = Ustrchr(s, '\n')))
+ {
+ if(!cutthrough_puts(s, s2-s) || !cutthrough_put_nl())
+ return FALSE;
+ s = s2+1;
+ }
+return TRUE;
+}
+
+
/* Buffered send of headers. Return success boolean. */
/* Expands newlines to wire format (CR,NL). */
/* Also sends header-terminating blank line. */
BOOL
cutthrough_headers_send( void )
{
-header_line * h;
-uschar * cp1, * cp2;
-
if(cutthrough_fd < 0)
return FALSE;
-for(h= header_list; h != NULL; h= h->next)
- if(h->type != htype_old && h->text != NULL)
- for (cp1 = h->text; *cp1 && (cp2 = Ustrchr(cp1, '\n')); cp1 = cp2+1)
- if( !cutthrough_puts(cp1, cp2-cp1)
- || !cutthrough_put_nl())
- return FALSE;
+/* We share a routine with the mainline transport to handle header add/remove/rewrites,
+ but having a separate buffered-output function (for now)
+*/
+HDEBUG(D_acl) debug_printf("----------- start cutthrough headers send -----------\n");
+
+if (!transport_headers_send(&cutthrough_addr, cutthrough_fd,
+ cutthrough_addr.transport->add_headers, cutthrough_addr.transport->remove_headers,
+ &cutthrough_write_chunk, TRUE,
+ cutthrough_addr.transport->rewrite_rules, cutthrough_addr.transport->rewrite_existflags))
+ return FALSE;
-HDEBUG(D_transport|D_acl|D_v) debug_printf(" SMTP>>(nl)\n");
-return cutthrough_put_nl();
+HDEBUG(D_acl) debug_printf("----------- done cutthrough headers send ------------\n");
+return TRUE;
}
if (address[0] == 0) return OK;
+/* Flip the legacy TLS-related variables over to the outbound set in case
+they're used in the context of a transport used by verification. Reset them
+at exit from this routine. */
+
+tls_modify_variables(&tls_out);
+
/* Save a copy of the sender address for re-instating if we change it to <>
while verifying a sender address (a nice bit of self-reference there). */
string_is_ip_address(host->name, NULL) != 0)
(void)host_find_byname(host, NULL, flags, &canonical_name, TRUE);
else
+ {
+ uschar * d_request = NULL, * d_require = NULL;
+ if (Ustrcmp(addr->transport->driver_name, "smtp") == 0)
+ {
+ smtp_transport_options_block * ob =
+ (smtp_transport_options_block *)
+ addr->transport->options_block;
+ d_request = ob->dnssec_request_domains;
+ d_require = ob->dnssec_require_domains;
+ }
+
(void)host_find_bydns(host, NULL, flags, NULL, NULL, NULL,
- &canonical_name, NULL);
+ d_request, d_require, &canonical_name, NULL);
+ }
}
}
}
}
cancel_cutthrough_connection("routing hard fail");
- if (!full_info) return copy_error(vaddr, addr, FAIL);
- else yield = FAIL;
+ if (!full_info)
+ {
+ yield = copy_error(vaddr, addr, FAIL);
+ goto out;
+ }
+ else yield = FAIL;
}
/* Soft failure */
}
cancel_cutthrough_connection("routing soft fail");
- if (!full_info) return copy_error(vaddr, addr, DEFER);
- else if (yield == OK) yield = DEFER;
+ if (!full_info)
+ {
+ yield = copy_error(vaddr, addr, DEFER);
+ goto out;
+ }
+ else if (yield == OK) yield = DEFER;
}
/* If we are handling EXPN, we do not want to continue to route beyond
if (addr_new == NULL) ok_prefix = US"250 ";
respond_printf(f, "%s<%s>\r\n", ok_prefix, addr2->address);
}
- return OK;
+ yield = OK;
+ goto out;
}
/* Successful routing other than EXPN. */
of $address_data to be that of the child */
vaddr->p.address_data = addr->p.address_data;
- return OK;
+ yield = OK;
+ goto out;
}
}
} /* Loop for generated addresses */
if (allok && addr_local == NULL && addr_remote == NULL)
{
fprintf(f, "mail to %s is discarded\n", address);
- return yield;
+ goto out;
}
for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++)
}
}
-/* Will be DEFER or FAIL if any one address has, only for full_info (which is
+/* Yield will be DEFER or FAIL if any one address has, only for full_info (which is
the -bv or -bt case). */
+out:
+tls_modify_variables(&tls_in);
+
return yield;
}
}
+/*************************************************
+* Check header names for 8-bit characters *
+*************************************************/
+
+/* This function checks for invalid charcters in header names. See
+RFC 5322, 2.2. and RFC 6532, 3.
+
+Arguments:
+ msgptr where to put an error message
+
+Returns: OK
+ FAIL
+*/
+
+int
+verify_check_header_names_ascii(uschar **msgptr)
+{
+header_line *h;
+uschar *colon, *s;
+
+for (h = header_list; h != NULL; h = h->next)
+ {
+ colon = Ustrchr(h->text, ':');
+ for(s = h->text; s < colon; s++)
+ {
+ if ((*s < 33) || (*s > 126))
+ {
+ *msgptr = string_sprintf("Invalid character in header \"%.*s\" found",
+ colon - h->text, h->text);
+ return FAIL;
+ }
+ }
+ }
+return OK;
+}
/*************************************************
* Check for blind recipients *
/* In case this is the first time the DNS resolver is being used. */
-dns_init(FALSE, FALSE);
+dns_init(FALSE, FALSE, FALSE); /*XXX dnssec? */
/* Loop through all the domains supplied, until something matches */
return FAIL;
}
+/* vi: aw ai sw=2
+*/
/* End of verify.c */