Tweak debug output
[exim.git] / src / src / retry.c
index dc39813fba731687cfc301e7b62ae8fbf577d213..a34bf80ca403719cdbbacc3300758e0b9c0fca01 100644 (file)
@@ -2,8 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 /* 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. */
 
@@ -126,15 +128,14 @@ retry_check_address(const uschar *domain, host_item *host, uschar *portstring,
 {
 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. */
 
@@ -144,9 +145,9 @@ host->status = hstatus_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 */
 
@@ -170,7 +171,7 @@ if ((node = tree_search(tree_unusable, host_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");
@@ -291,7 +292,7 @@ Returns:  nothing
 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;
@@ -580,7 +581,7 @@ for (int i = 0; i < 3; i++)
         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)
           {
@@ -654,19 +655,21 @@ for (int i = 0; i < 3; i++)
          ? 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;
@@ -674,7 +677,7 @@ for (int i = 0; i < 3; i++)
           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 */
 
@@ -805,15 +808,17 @@ for (int i = 0; i < 3; i++)
         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. */