string_printing(addr->peerdn), US"\"");
#endif
+ if (addr->authenticator)
+ {
+ s = string_append(s, &size, &ptr, 2, US" A=", addr->authenticator);
+ if (addr->auth_id)
+ {
+ s = string_append(s, &size, &ptr, 2, US":", addr->auth_id);
+ if (log_extra_selector & LX_smtp_mailauth && addr->auth_sndr)
+ s = string_append(s, &size, &ptr, 2, US":", addr->auth_sndr);
+ }
+ }
+
if ((log_extra_selector & LX_smtp_confirmation) != 0 &&
addr->message != NULL)
{
int i;
int local_part_length = Ustrlen(addr2->local_part);
uschar *s;
+ int ret;
- (void)write(pfd[pipe_write], (void *)&(addr2->transport_return), sizeof(int));
- (void)write(pfd[pipe_write], (void *)&transport_count, sizeof(transport_count));
- (void)write(pfd[pipe_write], (void *)&(addr2->flags), sizeof(addr2->flags));
- (void)write(pfd[pipe_write], (void *)&(addr2->basic_errno), sizeof(int));
- (void)write(pfd[pipe_write], (void *)&(addr2->more_errno), sizeof(int));
- (void)write(pfd[pipe_write], (void *)&(addr2->special_action), sizeof(int));
- (void)write(pfd[pipe_write], (void *)&(addr2->transport),
- sizeof(transport_instance *));
+ if( (ret = write(pfd[pipe_write], (void *)&(addr2->transport_return), sizeof(int))) != sizeof(int)
+ || (ret = write(pfd[pipe_write], (void *)&transport_count, sizeof(transport_count))) != sizeof(transport_count)
+ || (ret = write(pfd[pipe_write], (void *)&(addr2->flags), sizeof(addr2->flags))) != sizeof(addr2->flags)
+ || (ret = write(pfd[pipe_write], (void *)&(addr2->basic_errno), sizeof(int))) != sizeof(int)
+ || (ret = write(pfd[pipe_write], (void *)&(addr2->more_errno), sizeof(int))) != sizeof(int)
+ || (ret = write(pfd[pipe_write], (void *)&(addr2->special_action), sizeof(int))) != sizeof(int)
+ || (ret = write(pfd[pipe_write], (void *)&(addr2->transport),
+ sizeof(transport_instance *))) != sizeof(transport_instance *)
/* For a file delivery, pass back the local part, in case the original
was only part of the final delivery path. This gives more complete
logging. */
- if (testflag(addr2, af_file))
- {
- (void)write(pfd[pipe_write], (void *)&local_part_length, sizeof(int));
- (void)write(pfd[pipe_write], addr2->local_part, local_part_length);
- }
+ || (testflag(addr2, af_file)
+ && ( (ret = write(pfd[pipe_write], (void *)&local_part_length, sizeof(int))) != sizeof(int)
+ || (ret = write(pfd[pipe_write], addr2->local_part, local_part_length)) != local_part_length
+ )
+ )
+ )
+ log_write(0, LOG_MAIN|LOG_PANIC, "Failed writing transport results to pipe: %s\n",
+ ret == -1 ? strerror(errno) : "short write");
/* Now any messages */
for (i = 0, s = addr2->message; i < 2; i++, s = addr2->user_message)
{
int message_length = (s == NULL)? 0 : Ustrlen(s) + 1;
- (void)write(pfd[pipe_write], (void *)&message_length, sizeof(int));
- if (message_length > 0) (void)write(pfd[pipe_write], s, message_length);
+ if( (ret = write(pfd[pipe_write], (void *)&message_length, sizeof(int))) != sizeof(int)
+ || (message_length > 0 && (ret = write(pfd[pipe_write], s, message_length)) != message_length)
+ )
+ log_write(0, LOG_MAIN|LOG_PANIC, "Failed writing transport results to pipe: %s\n",
+ ret == -1 ? strerror(errno) : "short write");
}
}
break;
#endif
+ case 'C': /* client authenticator information */
+ switch (*ptr++)
+ {
+ case '1':
+ addr->authenticator = (*ptr)? string_copy(ptr) : NULL;
+ break;
+ case '2':
+ addr->auth_id = (*ptr)? string_copy(ptr) : NULL;
+ break;
+ case '3':
+ addr->auth_sndr = (*ptr)? string_copy(ptr) : NULL;
+ break;
+ }
+ while (*ptr++);
+ break;
+
case 'A':
if (addr == NULL)
{
+static void
+rmt_dlv_checked_write(int fd, void * buf, int size)
+{
+int ret = write(fd, buf, size);
+if(ret != size)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed writing transport result to pipe: %s\n",
+ ret == -1 ? strerror(errno) : "short write");
+}
+
/*************************************************
* Do remote deliveries *
*************************************************/
deliver_set_expansions(addr);
+ /* Ensure any transport-set auth info is fresh */
+ addr->authenticator = addr->auth_id = addr->auth_sndr = NULL;
+
/* Compute the return path, expanding a new one if required. The old one
must be set first, as it might be referred to in the expansion. */
{
if (h->address == NULL || h->status < hstatus_unusable) continue;
sprintf(CS big_buffer, "H%c%c%s", h->status, h->why, h->address);
- (void)write(fd, big_buffer, Ustrlen(big_buffer+3) + 4);
+ rmt_dlv_checked_write(fd, big_buffer, Ustrlen(big_buffer+3) + 4);
}
/* The number of bytes written. This is the same for each address. Even
big_buffer[0] = 'S';
memcpy(big_buffer+1, &transport_count, sizeof(transport_count));
- (void)write(fd, big_buffer, sizeof(transport_count) + 1);
+ rmt_dlv_checked_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)
{
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
{
sprintf(CS ptr, "%.512s", addr->peerdn);
while(*ptr++);
}
- (void)write(fd, big_buffer, ptr - big_buffer);
+ rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
}
#endif
+ if (client_authenticator)
+ {
+ ptr = big_buffer;
+ sprintf(CS big_buffer, "C1%.64s", client_authenticator);
+ while(*ptr++);
+ rmt_dlv_checked_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++);
+ rmt_dlv_checked_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++);
+ rmt_dlv_checked_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)
sprintf(CS ptr, "%.512s", r->message);
while(*ptr++);
}
- (void)write(fd, big_buffer, ptr - big_buffer);
+ rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
}
/* The rest of the information goes in an 'A' item. */
memcpy(ptr, &(addr->host_used->port), sizeof(addr->host_used->port));
ptr += sizeof(addr->host_used->port);
}
- (void)write(fd, big_buffer, ptr - big_buffer);
+ rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
}
/* Add termination flag, close the pipe, and that's it. The character
big_buffer[0] = 'Z';
big_buffer[1] = (continue_transport == NULL)? '0' : '1';
- (void)write(fd, big_buffer, 2);
+ rmt_dlv_checked_write(fd, big_buffer, 2);
(void)close(fd);
exit(EXIT_SUCCESS);
}
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. */
that the mode is correct - the group setting doesn't always seem to get
set automatically. */
- (void)fcntl(journal_fd, F_SETFD, fcntl(journal_fd, F_GETFD) | FD_CLOEXEC);
- (void)fchown(journal_fd, exim_uid, exim_gid);
- (void)fchmod(journal_fd, SPOOL_MODE);
+ if( fcntl(journal_fd, F_SETFD, fcntl(journal_fd, F_GETFD) | FD_CLOEXEC)
+ || fchown(journal_fd, exim_uid, exim_gid)
+ || fchmod(journal_fd, SPOOL_MODE)
+ )
+ {
+ int ret = Uunlink(spoolname);
+ log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't set perms on journal file %s: %s",
+ spoolname, strerror(errno));
+ if(ret && errno != ENOENT)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to unlink %s: %s",
+ spoolname, strerror(errno));
+ return DELIVER_NOT_ATTEMPTED;
+ }
}
+
/* Now we can get down to the business of actually doing deliveries. Local
deliveries are done first, then remote ones. If ever the problems of how to
handle fallback transports are figured out, this section can be put into a loop
released. */
search_tidyup();
+acl_where = ACL_WHERE_UNKNOWN;
return final_yield;
}