+/* If msg is NULL this is a delivery log and logchar is used. Otherwise
+this is a nonstandard call; no two-characher delivery flag is written
+but sender-host and sender are prefixed and "msg" is inserted in the log line.
+
+Arguments:
+ flags passed to log_write()
+*/
+void
+delivery_log(int flags, address_item * addr, int logchar, uschar * msg)
+{
+uschar *log_address;
+int size = 256; /* Used for a temporary, */
+int ptr = 0; /* expanding buffer, for */
+uschar *s; /* building log lines; */
+void *reset_point; /* released afterwards. */
+
+
+/* Log the delivery on the main log. We use an extensible string to build up
+the log line, and reset the store afterwards. Remote deliveries should always
+have a pointer to the host item that succeeded; local deliveries can have a
+pointer to a single host item in their host list, for use by the transport. */
+
+s = reset_point = store_get(size);
+
+log_address = string_log_address(addr, (log_write_selector & L_all_parents) != 0, TRUE);
+if (msg)
+ s = string_append(s, &size, &ptr, 3, host_and_ident(TRUE), US" ", log_address);
+else
+ {
+ s[ptr++] = logchar;
+ s = string_append(s, &size, &ptr, 2, US"> ", log_address);
+ }
+
+if ((log_extra_selector & LX_sender_on_delivery) != 0 || msg)
+ s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">");
+
+#ifdef EXPERIMENTAL_SRS
+if(addr->p.srs_sender)
+ s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->p.srs_sender, US">");
+#endif
+
+/* You might think that the return path must always be set for a successful
+delivery; indeed, I did for some time, until this statement crashed. The case
+when it is not set is for a delivery to /dev/null which is optimised by not
+being run at all. */
+
+if (used_return_path != NULL &&
+ (log_extra_selector & LX_return_path_on_delivery) != 0)
+ s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
+
+if (msg)
+ s = string_append(s, &size, &ptr, 2, US" ", msg);
+
+/* For a delivery from a system filter, there may not be a router */
+if (addr->router != NULL)
+ s = string_append(s, &size, &ptr, 2, US" R=", addr->router->name);
+
+s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name);
+
+if ((log_extra_selector & LX_delivery_size) != 0)
+ s = string_append(s, &size, &ptr, 2, US" S=",
+ string_sprintf("%d", transport_count));
+
+/* Local delivery */
+
+if (addr->transport->info->local)
+ {
+ if (addr->host_list != NULL)
+ s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name);
+ if (addr->shadow_message != NULL)
+ s = string_cat(s, &size, &ptr, addr->shadow_message,
+ Ustrlen(addr->shadow_message));
+ }
+
+/* Remote delivery */
+
+else
+ {
+ if (addr->host_used != NULL)
+ {
+ s = string_append(s, &size, &ptr, 5, US" H=", addr->host_used->name,
+ US" [", addr->host_used->address, US"]");
+ if ((log_extra_selector & LX_outgoing_port) != 0)
+ s = string_append(s, &size, &ptr, 2, US":", string_sprintf("%d",
+ addr->host_used->port));
+ if (continue_sequence > 1)
+ s = string_cat(s, &size, &ptr, US"*", 1);
+ }
+
+ #ifdef SUPPORT_TLS
+ if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
+ s = string_append(s, &size, &ptr, 2, US" X=", addr->cipher);
+ if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
+ addr->cipher != NULL)
+ s = string_append(s, &size, &ptr, 2, US" CV=",
+ testflag(addr, af_cert_verified)? "yes":"no");
+ if ((log_extra_selector & LX_tls_peerdn) != 0 && addr->peerdn != NULL)
+ s = string_append(s, &size, &ptr, 3, US" DN=\"",
+ string_printing(addr->peerdn), US"\"");
+ #endif
+
+ if (smtp_authenticated)
+ {
+ s = string_append(s, &size, &ptr, 2, US" A=", client_authenticator);
+ if (client_authenticated_id)
+ {
+ s = string_append(s, &size, &ptr, 2, US":", client_authenticated_id);
+ if (log_extra_selector & LX_smtp_mailauth && client_authenticated_sender)
+ s = string_append(s, &size, &ptr, 2, US":", client_authenticated_sender);
+ }
+ }
+
+ if ((log_extra_selector & LX_smtp_confirmation) != 0 &&
+ addr->message != NULL)
+ {
+ int i;
+ uschar *p = big_buffer;
+ uschar *ss = addr->message;
+ *p++ = '\"';
+ for (i = 0; i < 100 && ss[i] != 0; i++)
+ {
+ if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\';
+ *p++ = ss[i];
+ }
+ *p++ = '\"';
+ *p = 0;
+ s = string_append(s, &size, &ptr, 2, US" C=", big_buffer);
+ }
+ }
+
+/* Time on queue and actual time taken to deliver */
+
+if ((log_extra_selector & LX_queue_time) != 0)
+ {
+ s = string_append(s, &size, &ptr, 2, US" QT=",
+ readconf_printtime(time(NULL) - received_time));
+ }
+
+if ((log_extra_selector & LX_deliver_time) != 0)
+ {
+ s = string_append(s, &size, &ptr, 2, US" DT=",
+ readconf_printtime(addr->more_errno));
+ }
+
+/* string_cat() always leaves room for the terminator. Release the
+store we used to build the line after writing it. */
+
+s[ptr] = 0;
+log_write(0, flags, "%s", s);
+store_reset(reset_point);
+return;
+}
+
+
+
/*************************************************
* Actions at the end of handling an address *
*************************************************/
(void)close(addr->return_file);
}
-/* Create the address string for logging. Must not do this earlier, because
-an OK result may be changed to FAIL when a pipe returns text. */
-
-log_address = string_log_address(addr,
- (log_write_selector & L_all_parents) != 0, result == OK);
-
/* The sucess case happens only after delivery by a transport. */
if (result == OK)
child_done(addr, now);
}
- /* Log the delivery on the main log. We use an extensible string to build up
- the log line, and reset the store afterwards. Remote deliveries should always
- have a pointer to the host item that succeeded; local deliveries can have a
- pointer to a single host item in their host list, for use by the transport. */
-
- s = reset_point = store_get(size);
- s[ptr++] = logchar;
-
- s = string_append(s, &size, &ptr, 2, US"> ", log_address);
-
- if ((log_extra_selector & LX_sender_on_delivery) != 0)
- s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">");
-
- #ifdef EXPERIMENTAL_SRS
- if(addr->p.srs_sender)
- s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->p.srs_sender, US">");
- #endif
-
- /* You might think that the return path must always be set for a successful
- delivery; indeed, I did for some time, until this statement crashed. The case
- when it is not set is for a delivery to /dev/null which is optimised by not
- being run at all. */
-
- if (used_return_path != NULL &&
- (log_extra_selector & LX_return_path_on_delivery) != 0)
- s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
-
- /* For a delivery from a system filter, there may not be a router */
-
- if (addr->router != NULL)
- s = string_append(s, &size, &ptr, 2, US" R=", addr->router->name);
-
- s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name);
-
- if ((log_extra_selector & LX_delivery_size) != 0)
- s = string_append(s, &size, &ptr, 2, US" S=",
- string_sprintf("%d", transport_count));
-
- /* Local delivery */
-
- if (addr->transport->info->local)
- {
- if (addr->host_list != NULL)
- s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name);
- if (addr->shadow_message != NULL)
- s = string_cat(s, &size, &ptr, addr->shadow_message,
- Ustrlen(addr->shadow_message));
- }
-
- /* Remote delivery */
-
- else
- {
- if (addr->host_used != NULL)
- {
- s = string_append(s, &size, &ptr, 5, US" H=", addr->host_used->name,
- US" [", addr->host_used->address, US"]");
- if ((log_extra_selector & LX_outgoing_port) != 0)
- s = string_append(s, &size, &ptr, 2, US":", string_sprintf("%d",
- addr->host_used->port));
- if (continue_sequence > 1)
- s = string_cat(s, &size, &ptr, US"*", 1);
- }
-
- #ifdef SUPPORT_TLS
- if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
- s = string_append(s, &size, &ptr, 2, US" X=", addr->cipher);
- if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
- addr->cipher != NULL)
- s = string_append(s, &size, &ptr, 2, US" CV=",
- testflag(addr, af_cert_verified)? "yes":"no");
- if ((log_extra_selector & LX_tls_peerdn) != 0 && addr->peerdn != NULL)
- s = string_append(s, &size, &ptr, 3, US" DN=\"",
- string_printing(addr->peerdn), US"\"");
- #endif
-
- if ((log_extra_selector & LX_smtp_confirmation) != 0 &&
- addr->message != NULL)
- {
- int i;
- uschar *p = big_buffer;
- uschar *ss = addr->message;
- *p++ = '\"';
- for (i = 0; i < 100 && ss[i] != 0; i++)
- {
- if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\';
- *p++ = ss[i];
- }
- *p++ = '\"';
- *p = 0;
- s = string_append(s, &size, &ptr, 2, US" C=", big_buffer);
- }
- }
-
- /* Time on queue and actual time taken to deliver */
-
- if ((log_extra_selector & LX_queue_time) != 0)
- {
- s = string_append(s, &size, &ptr, 2, US" QT=",
- readconf_printtime(time(NULL) - received_time));
- }
-
- if ((log_extra_selector & LX_deliver_time) != 0)
- {
- s = string_append(s, &size, &ptr, 2, US" DT=",
- readconf_printtime(addr->more_errno));
- }
-
- /* string_cat() always leaves room for the terminator. Release the
- store we used to build the line after writing it. */
-
- s[ptr] = 0;
- log_write(0, LOG_MAIN, "%s", s);
- store_reset(reset_point);
+ delivery_log(LOG_MAIN, addr, logchar, NULL);
}
log. */
s = reset_point = store_get(size);
+
+ /* Create the address string for logging. Must not do this earlier, because
+ an OK result may be changed to FAIL when a pipe returns text. */
+
+ log_address = string_log_address(addr,
+ (log_write_selector & L_all_parents) != 0, result == OK);
+
s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address));
/* Either driver_name contains something and driver_kind contains
/* Build up the log line for the message and main logs */
s = reset_point = store_get(size);
+
+ /* Create the address string for logging. Must not do this earlier, because
+ an OK result may be changed to FAIL when a pipe returns text. */
+
+ log_address = string_log_address(addr,
+ (log_write_selector & L_all_parents) != 0, result == OK);
+
s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address));
if ((log_extra_selector & LX_sender_on_delivery) != 0)
va_start(ap, format);
if (!string_vformat(buffer, sizeof(buffer), CS format, ap))
log_write(0, LOG_MAIN|LOG_PANIC_DIE,
- "common_error expansion was longer than %d", sizeof(buffer));
+ "common_error expansion was longer than " SIZE_T_FMT, sizeof(buffer));
va_end(ap);
addr->message = string_copy(buffer);
}
break;
#endif
+ case 'C': /* client authenticator information */
+ switch (*ptr++)
+ {
+ case '1':
+ smtp_authenticated = TRUE;
+ client_authenticator = (*ptr)? string_copy(ptr) : NULL;
+ break;
+ case '2':
+ client_authenticated_id = (*ptr)? string_copy(ptr) : NULL;
+ break;
+ case '3':
+ client_authenticated_sender = (*ptr)? string_copy(ptr) : NULL;
+ break;
+ }
+ while (*ptr++);
+ break;
+
case 'A':
if (addr == NULL)
{
memcpy(big_buffer+1, &transport_count, sizeof(transport_count));
(void)write(fd, big_buffer, sizeof(transport_count) + 1);
- /* Information about what happened to each address. Three item types are
- used: an optional 'X' item first, for TLS information, followed by 'R'
- items for any retry settings, and finally an 'A' item for the remaining
- data. */
+ /* Information about what happened to each address. Four item types are
+ used: an optional 'X' item first, for TLS information, then an optional "C"
+ item for any client-auth info followed by 'R' items for any retry settings,
+ and finally an 'A' item for the remaining data. */
for(; addr != NULL; addr = addr->next)
{
/* The certificate verification status goes into the flags */
- if (tls_certificate_verified) setflag(addr, af_cert_verified);
+ if (tls_out.certificate_verified) setflag(addr, af_cert_verified);
/* Use an X item only if there's something to send */
if (addr->cipher != NULL)
{
ptr = big_buffer;
- *ptr++ = 'X';
- sprintf(CS ptr, "%.128s", addr->cipher);
+ sprintf(CS ptr, "X%.128s", addr->cipher);
while(*ptr++);
if (addr->peerdn == NULL) *ptr++ = 0; else
{
}
#endif
+ if (client_authenticator)
+ {
+ ptr = big_buffer;
+ sprintf(CS big_buffer, "C1%.64s", client_authenticator);
+ while(*ptr++);
+ (void)write(fd, big_buffer, ptr - big_buffer);
+ }
+ if (client_authenticated_id)
+ {
+ ptr = big_buffer;
+ sprintf(CS big_buffer, "C2%.64s", client_authenticated_id);
+ while(*ptr++);
+ (void)write(fd, big_buffer, ptr - big_buffer);
+ }
+ if (client_authenticated_sender)
+ {
+ ptr = big_buffer;
+ sprintf(CS big_buffer, "C3%.64s", client_authenticated_sender);
+ while(*ptr++);
+ (void)write(fd, big_buffer, ptr - big_buffer);
+ }
+
/* Retry information: for most success cases this will be null. */
for (r = addr->retries; r != NULL; r = r->next)
int process_recipients = RECIP_ACCEPT;
open_db dbblock;
open_db *dbm_file;
+extern int acl_where;
uschar *info = (queue_run_pid == (pid_t)0)?
string_sprintf("delivering %s", id) :
update_spool = FALSE;
remove_journal = TRUE;
+/* Set a known context for any ACLs we call via expansions */
+acl_where = ACL_WHERE_DELIVERY;
+
/* Reset the random number generator, so that if several delivery processes are
started from a queue runner that has already used random numbers (for sorting),
they don't all get the same sequence. */
released. */
search_tidyup();
+acl_where = ACL_WHERE_UNKNOWN;
return final_yield;
}