directory if it does not exist. From release 4.21, normal message logs should
be created when the message is received.
directory if it does not exist. From release 4.21, normal message logs should
be created when the message is received.
+ fd = Uopen(filename,
+#ifdef O_CLOEXEC
+ O_CLOEXEC |
+#endif
+#ifdef O_NOFOLLOW
+ O_NOFOLLOW |
+#endif
+ O_WRONLY|O_APPEND|O_CREAT, mode);
+ if (fd >= 0)
+ {
+ /* Set the close-on-exec flag and change the owner to the exim uid/gid (this
+ function is called as root). Double check the mode, because the group setting
+ doesn't always get set automatically. */
+
+#ifndef O_CLOEXEC
+ (void)fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+#endif
+ if (fchown(fd, exim_uid, exim_gid) < 0)
+ {
+ *error = US"chown";
+ return -1;
+ }
+ if (fchmod(fd, mode) < 0)
+ {
+ *error = US"chmod";
+ return -1;
+ }
+ return fd;
+ }
+ if (errno != ENOENT)
+ break;
+
(void)directory_make(spool_directory,
spool_sname(US"msglog", message_subdir),
MSGLOG_DIRECTORY_MODE, TRUE);
(void)directory_make(spool_directory,
spool_sname(US"msglog", message_subdir),
MSGLOG_DIRECTORY_MODE, TRUE);
-/* Set the close-on-exec flag and change the owner to the exim uid/gid (this
-function is called as root). Double check the mode, because the group setting
-doesn't always get set automatically. */
-
-if (fd >= 0)
- {
- (void)fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
- if (fchown(fd, exim_uid, exim_gid) < 0)
- {
- *error = US"chown";
- return -1;
- }
- if (fchmod(fd, mode) < 0)
- {
- *error = US"chmod";
- return -1;
- }
- }
-else *error = US"create";
-
-return fd;
+*error = US"create";
+return -1;
/* We start with just the local part for pipe, file, and reply deliveries, and
for successful local deliveries from routers that have the log_as_local flag
set. File deliveries from filters can be specified as non-absolute paths in
/* We start with just the local part for pipe, file, and reply deliveries, and
for successful local deliveries from routers that have the log_as_local flag
set. File deliveries from filters can be specified as non-absolute paths in
before this happens (expansion failure) the local part will not be updated, and
so won't necessarily look like a path. Add extra text for this case. */
before this happens (expansion failure) the local part will not be updated, and
so won't necessarily look like a path. Add extra text for this case. */
- log_write(0, LOG_MAIN|LOG_PANIC, "Failed writing transport results to pipe: %s\n",
+ log_write(0, LOG_MAIN|LOG_PANIC, "Failed writing transport results to pipe: %s",
if( (ret = write(pfd[pipe_write], &message_length, sizeof(int))) != sizeof(int)
|| message_length > 0 && (ret = write(pfd[pipe_write], s, message_length)) != message_length
)
if( (ret = write(pfd[pipe_write], &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",
+ log_write(0, LOG_MAIN|LOG_PANIC, "Failed writing transport results to pipe: %s",
- int local_part_length;
- len = read(pfd[pipe_read], &local_part_length, sizeof(int));
- len = read(pfd[pipe_read], big_buffer, local_part_length);
- big_buffer[local_part_length] = 0;
+ int llen;
+ if ( read(pfd[pipe_read], &llen, sizeof(int)) != sizeof(int)
+ || llen > 64*4 /* limit from rfc 5821, times I18N factor */
+ )
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "bad local_part length read"
+ " from delivery subprocess");
+ break;
+ }
+ /* sanity-checked llen so disable the Coverity error */
+ /* coverity[tainted_data] */
+ if (read(pfd[pipe_read], big_buffer, llen) != llen)
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "bad local_part read"
+ " from delivery subprocess");
+ break;
+ }
+ big_buffer[llen] = 0;
/* minimum size to read is header size including id, subid and length */
int required = PIPE_HEADER_SIZE;
/* minimum size to read is header size including id, subid and length */
int required = PIPE_HEADER_SIZE;
There will be only one read if we get all the available data (i.e. don't
fill the buffer completely). */
There will be only one read if we get all the available data (i.e. don't
fill the buffer completely). */
/* If the length is zero (eof or no-more-data), just process what we
already have. Note that if the process is still running and we have
read all the data in the pipe (but less that "available") then we
/* If the length is zero (eof or no-more-data), just process what we
already have. Note that if the process is still running and we have
read all the data in the pipe (but less that "available") then we
- debug_printf("header read id:%c,subid:%c,size:%s,required:%d,remaining:%d,unfinished:%d\n",
- id, subid, header+2, required, remaining, unfinished);
+ debug_printf("header read id:%c,subid:%c,size:%s,required:%d,remaining:%d,finished:%d\n",
+ id, subid, header+2, required, remaining, finished);
/* is there room for the dataset we want to read ? */
if (required > big_buffer_size - PIPE_HEADER_SIZE)
/* is there room for the dataset we want to read ? */
if (required > big_buffer_size - PIPE_HEADER_SIZE)
- /* we wrote all datasets with atomic write() calls
- remaining < required only happens if big_buffer was too small
- to get all available data from pipe. unfinished has to be true
- as well. */
+ /* We wrote all datasets with atomic write() calls. Remaining < required only
+ happens if big_buffer was too small to get all available data from pipe;
+ finished has to be false as well. */
+
pid, addr->transport->driver_name, required, remaining);
done = TRUE;
break;
}
pid, addr->transport->driver_name, required, remaining);
done = TRUE;
break;
}
if (Ustrcmp(r->key, ptr+1) == 0) /* Found item with same key */
{
if ((r->flags & rf_delete) == 0) break; /* It was not "delete" */
if (Ustrcmp(r->key, ptr+1) == 0) /* Found item with same key */
{
if ((r->flags & rf_delete) == 0) break; /* It was not "delete" */
/* We want to add a delete item only if there is no non-delete item;
however we still have to step ptr through the data. */
/* We want to add a delete item only if there is no non-delete item;
however we still have to step ptr through the data. */
exp_bool(addr,
US"transport", next->transport->name, D_transport,
US"multi_domain", next->transport->multi_domain,
exp_bool(addr,
US"transport", next->transport->name, D_transport,
US"multi_domain", next->transport->multi_domain,
{
uschar * fname = spool_fname(US"input", message_subdir, message_id, US"-D");
{
uschar * fname = spool_fname(US"input", message_subdir, message_id, US"-D");
- if ((deliver_datafile = Uopen(fname, O_RDWR | O_APPEND, 0)) < 0)
+ if ((deliver_datafile = Uopen(fname,
+#ifdef O_CLOEXEC
+ O_CLOEXEC |
+#endif
+ O_RDWR | O_APPEND, 0)) < 0)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed to reopen %s for remote "
"parallel delivery: %s", fname, strerror(errno));
}
/* Set the close-on-exec flag */
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed to reopen %s for remote "
"parallel delivery: %s", fname, strerror(errno));
}
/* Set the close-on-exec flag */
(void)fcntl(deliver_datafile, F_SETFD, fcntl(deliver_datafile, F_GETFD) |
FD_CLOEXEC);
(void)fcntl(deliver_datafile, F_SETFD, fcntl(deliver_datafile, F_GETFD) |
FD_CLOEXEC);
rmt_dlv_checked_write(fd, 'X', '1', big_buffer, ptr - big_buffer);
}
rmt_dlv_checked_write(fd, 'X', '1', big_buffer, ptr - big_buffer);
}
+ else if (continue_proxy_cipher)
+ {
+ ptr = big_buffer + sprintf(CS big_buffer, "%.128s", continue_proxy_cipher) + 1;
+ *ptr++ = 0;
+ rmt_dlv_checked_write(fd, 'X', '1', big_buffer, ptr - big_buffer);
+ }
+
addr->address = new_address;
addr->unique = string_copy(new_address);
addr->domain = deliver_domain;
addr->address = new_address;
addr->unique = string_copy(new_address);
addr->domain = deliver_domain;
Arguments:
id the id of the message to be delivered
forced TRUE if delivery was forced by an administrator; this overrides
Arguments:
id the id of the message to be delivered
forced TRUE if delivery was forced by an administrator; this overrides
{
uschar * fname = spool_fname(US"input", message_subdir, id, US"-J");
{
uschar * fname = spool_fname(US"input", message_subdir, id, US"-J");
- if ((jread = Ufopen(fname, "rb")))
+ if ( (journal_fd = Uopen(fname, O_RDWR|O_APPEND
+#ifdef O_CLOEXEC
+ | O_CLOEXEC
+#endif
+#ifdef O_NOFOLLOW
+ | O_NOFOLLOW
+#endif
+ , SPOOL_MODE)) >= 0
+ && lseek(journal_fd, 0, SEEK_SET) == 0
+ && (jread = fdopen(journal_fd, "rb"))
+ )
DEBUG(D_deliver) debug_printf("Previously delivered address %s taken from "
"journal file\n", big_buffer);
}
DEBUG(D_deliver) debug_printf("Previously delivered address %s taken from "
"journal file\n", big_buffer);
}
/* Panic-dies on error */
(void)spool_write_header(message_id, SW_DELIVERING, NULL);
}
/* Panic-dies on error */
(void)spool_write_header(message_id, SW_DELIVERING, NULL);
}
if (!tp)
p->message = string_sprintf("failed to find \"%s\" transport "
"for system filter delivery", tpname);
if (!tp)
p->message = string_sprintf("failed to find \"%s\" transport "
"for system filter delivery", tpname);
-/* If there are any deliveries to be done, open the journal file. This is used
-to record successful deliveries as soon as possible after each delivery is
-known to be complete. A file opened with O_APPEND is used so that several
-processes can run simultaneously.
+/* If there are any deliveries to be and we do not already have the journal
+file, create it. This is used to record successful deliveries as soon as
+possible after each delivery is known to be complete. A file opened with
+O_APPEND is used so that several processes can run simultaneously.
The journal is just insurance against crashes. When the spool file is
ultimately updated at the end of processing, the journal is deleted. If a
The journal is just insurance against crashes. When the spool file is
ultimately updated at the end of processing, the journal is deleted. If a
- uschar * fname = spool_fname(US"input", message_subdir, id, US"-J");
-
- if ((journal_fd = Uopen(fname, O_WRONLY|O_APPEND|O_CREAT, SPOOL_MODE)) <0)
- log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't open journal file %s: %s",
- fname, strerror(errno));
- return DELIVER_NOT_ATTEMPTED;
- }
+ uschar * fname = spool_fname(US"input", message_subdir, id, US"-J");
+
+ if ((journal_fd = Uopen(fname,
+#ifdef O_CLOEXEC
+ O_CLOEXEC |
+#endif
+ O_WRONLY|O_APPEND|O_CREAT|O_EXCL, SPOOL_MODE)) < 0)
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't open journal file %s: %s",
+ fname, strerror(errno));
+ return DELIVER_NOT_ATTEMPTED;
+ }
- /* Set the close-on-exec flag, make the file owned by Exim, and ensure
- that the mode is correct - the group setting doesn't always seem to get
- set automatically. */
+ /* Set the close-on-exec flag, make the file owned by Exim, and ensure
+ that the mode is correct - the group setting doesn't always seem to get
+ set automatically. */
- 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(fname);
- log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't set perms on journal file %s: %s",
- fname, strerror(errno));
- if(ret && errno != ENOENT)
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to unlink %s: %s",
- fname, strerror(errno));
- return DELIVER_NOT_ATTEMPTED;
+ if( fchown(journal_fd, exim_uid, exim_gid)
+ || fchmod(journal_fd, SPOOL_MODE)
+#ifndef O_CLOEXEC
+ || fcntl(journal_fd, F_SETFD, fcntl(journal_fd, F_GETFD) | FD_CLOEXEC)
+#endif
+ )
+ {
+ int ret = Uunlink(fname);
+ log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't set perms on journal file %s: %s",
+ fname, strerror(errno));
+ if(ret && errno != ENOENT)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to unlink %s: %s",
+ fname, strerror(errno));
+ return DELIVER_NOT_ATTEMPTED;
+ }
/* Otherwise, handle the sending of a message. Find the error address for
the first address, then send a message that includes all failed addresses
that have the same error address. Note the bounce_recipient is a global so
/* Otherwise, handle the sending of a message. Find the error address for
the first address, then send a message that includes all failed addresses
that have the same error address. Note the bounce_recipient is a global so
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to unlink %s: %s", fname,
strerror(errno));
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to unlink %s: %s", fname,
strerror(errno));