* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Functions concerned with retrying unsuccessful deliveries. */
{
BOOL yield = FALSE;
time_t now = time(NULL);
-uschar *host_key, *message_key;
-open_db dbblock;
-open_db *dbm_file;
-tree_node *node;
-dbdata_retry *host_retry_record, *message_retry_record;
+uschar * host_key, * message_key;
+open_db dbblock, * dbm_file;
+tree_node * node;
+dbdata_retry * host_retry_record, * message_retry_record;
*retry_host_key = *retry_message_key = NULL;
-DEBUG(D_transport|D_retry) debug_printf("checking status of %s\n", host->name);
+DEBUG(D_transport|D_retry) debug_printf("checking retry status of %s\n", host->name);
/* Do nothing if status already set; otherwise initialize status as usable. */
/* Generate the host key for the unusable tree and the retry database. Ensure
host names are lower cased (that's what %S does). */
-host_key = include_ip_address?
- string_sprintf("T:%S:%s%s", host->name, host->address, portstring) :
- string_sprintf("T:%S%s", host->name, portstring);
+host_key = include_ip_address
+ ? string_sprintf("T:%S:%s%s", host->name, host->address, portstring)
+ : string_sprintf("T:%S%s", host->name, portstring);
/* Generate the message-specific key */
/* Open the retry database, giving up if there isn't one. Otherwise, search for
the retry records, and then close the database again. */
-if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
+if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
{
DEBUG(D_deliver|D_retry|D_hints_lookup)
debug_printf("no retry data available\n");
void
retry_add_item(address_item *addr, uschar *key, int flags)
{
-retry_item *rti = store_get(sizeof(retry_item));
+retry_item * rti = store_get(sizeof(retry_item), GET_UNTAINTED);
host_item * host = addr->host_used;
rti->next = addr->retries;
*/
void
-retry_update(address_item **addr_defer, address_item **addr_failed,
- address_item **addr_succeed)
+retry_update(address_item ** addr_defer, address_item ** addr_failed,
+ address_item ** addr_succeed)
{
open_db dbblock;
open_db *dbm_file = NULL;
for (int i = 0; i < 3; i++)
{
- address_item *endaddr, *addr;
- address_item *last_first = NULL;
- address_item **paddr = i==0 ? addr_succeed :
- i==1 ? addr_failed : addr_defer;
- address_item **saved_paddr = NULL;
+ address_item * endaddr, *addr;
+ address_item * last_first = NULL;
+ address_item ** paddr = i==0 ? addr_succeed : i==1 ? addr_failed : addr_defer;
+ address_item ** saved_paddr = NULL;
DEBUG(D_retry) debug_printf("%s addresses:\n",
i == 0 ? "Succeeded" : i == 1 ? "Failed" : "Deferred");
reached their retry next try time. */
if (!dbm_file)
- dbm_file = dbfn_open(US"retry", O_RDWR, &dbblock, TRUE);
+ dbm_file = dbfn_open(US"retry", O_RDWR, &dbblock, TRUE, TRUE);
if (!dbm_file)
{
? US string_printing(rti->message)
: US"unknown error";
message_length = Ustrlen(message);
- if (message_length > 150) message_length = 150;
+ if (message_length > EXIM_DB_RLIMIT) message_length = EXIM_DB_RLIMIT;
/* Read a retry record from the database or construct a new one.
Ignore an old one if it is too old since it was last updated. */
- retry_record = dbfn_read(dbm_file, rti->key);
+ retry_record = dbfn_read_with_length(dbm_file, rti->key,
+ &message_space);
if ( retry_record
&& now - retry_record->time_stamp > retry_data_expire)
retry_record = NULL;
if (!retry_record)
{
- retry_record = store_get(sizeof(dbdata_retry) + message_length);
+ retry_record = store_get(sizeof(dbdata_retry) + message_length,
+ message);
message_space = message_length;
retry_record->first_failed = now;
retry_record->last_try = now;
retry_record->expired = FALSE;
retry_record->text[0] = 0; /* just in case */
}
- else message_space = Ustrlen(retry_record->text);
+ else message_space -= sizeof(dbdata_retry);
/* Compute how long this destination has been failing */
if (next_try - now > retry_interval_max)
next_try = now + retry_interval_max;
- /* If the new message length is greater than the previous one, we
- have to copy the record first. */
-
- if (message_length > message_space)
- {
- dbdata_retry *newr = store_get(sizeof(dbdata_retry) + message_length);
- memcpy(newr, retry_record, sizeof(dbdata_retry));
- retry_record = newr;
- }
+ /* If the new message length is greater than the previous one, we have
+ to copy the record first. If we're using an old one, the read used
+ tainted memory so we're ok to write into it. */
+
+ if (message_length > message_space)
+ {
+ dbdata_retry * newr =
+ store_get(sizeof(dbdata_retry) + message_length, message);
+ memcpy(newr, retry_record, sizeof(dbdata_retry));
+ retry_record = newr;
+ }
/* Set up the retry record; message_length may be less than the string
length for very long error strings. */