[exim-cvs] SECURITY: length limits on many cmdline options

Inizio della pagina
Delete this message
Reply to this message
Autore: Exim Git Commits Mailing List
Data:  
To: exim-cvs
Oggetto: [exim-cvs] SECURITY: length limits on many cmdline options
Gitweb: https://git.exim.org/exim.git/commitdiff/c1fb74d63ecf0cd1501e53352419bfdfd154b7ea
Commit:     c1fb74d63ecf0cd1501e53352419bfdfd154b7ea
Parent:     66c014bb0d4972b7d5915795dec376535089740c
Author:     Phil Pennock <phil+git@???>
AuthorDate: Thu Oct 29 18:11:35 2020 -0400
Committer:  Heiko Schlittermann (HS12-RIPE) <hs@???>
CommitDate: Thu May 27 21:30:23 2021 +0200


    SECURITY: length limits on many cmdline options


    We'll also now abort upon, rather than silently truncate, a driver name
    (router, transport, ACL, etc) encountered in the config which is longer than
    the 64-char limit.


    (cherry picked from commit ff8bef9ae2370db4a7873fe2ce573a607fe6999f)
    (cherry picked from commit a8bd24b96c2027fd839f95a9e6b3282453ae288e)
---
 doc/doc-docbook/spec.xfpt | 19 ++++++++++
 doc/doc-txt/ChangeLog     |  6 +++
 src/src/acl.c             |  4 +-
 src/src/exim.c            | 93 +++++++++++++++++++++++++++++++----------------
 src/src/exim.h            | 45 +++++++++++++++++++++++
 src/src/macro_predef.c    |  2 +-
 src/src/macros.h          |  6 ---
 src/src/malware.c         |  2 +-
 src/src/parse.c           |  8 ++--
 src/src/readconf.c        | 30 ++++++++++-----
 src/src/transport.c       |  9 +++--
 11 files changed, 165 insertions(+), 59 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 9b8c92b..61abb70 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -51,6 +51,8 @@
.set ACL "access control lists (ACLs)"
.set I "&nbsp;&nbsp;&nbsp;&nbsp;"

+.set drivernamemax "64"
+
.macro copyyear
2020
.endmacro
@@ -18802,6 +18804,11 @@ which the preconditions are tested. The order of expansion of the options that
provide data for a transport is: &%errors_to%&, &%headers_add%&,
&%headers_remove%&, &%transport%&.

+.new
+The name of a router is limited to be &drivernamemax; ASCII characters long;
+prior to Exim 4.95 names would be silently truncated at this length, but now
+it is enforced.
+.wen


.option address_data routers string&!! unset
@@ -22345,6 +22352,12 @@ and &$original_domain$& is never set.
.scindex IIDgenoptra1 "generic options" "transport"
.scindex IIDgenoptra2 "options" "generic; for transports"
.scindex IIDgenoptra3 "transport" "generic options for"
+.new
+The name of a transport is limited to be &drivernamemax; ASCII characters long;
+prior to Exim 4.95 names would be silently truncated at this length, but now
+it is enforced.
+.wen
+
The following generic options apply to all transports:


@@ -27181,6 +27194,12 @@ permitted to use it as a relay. SMTP authentication is not of relevance to the
transfer of mail between servers that have no managerial connection with each
other.

+.new
+The name of an authenticator is limited to be &drivernamemax; ASCII characters long;
+prior to Exim 4.95 names would be silently truncated at this length, but now
+it is enforced.
+.wen
+
 .cindex "AUTH" "description of"
 .cindex "ESMTP extensions" AUTH
 Very briefly, the way SMTP authentication works is as follows:
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 58ba70f..4c6eb81 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -263,6 +263,12 @@ PP/02 Bug 2643: Correct TLS DH constants.
       incorrect Diffie-Hellman constants in the Exim source.
       Reported by kylon94, code-gen tool fix by Simon Arlott.


+PP/03 Fix Linux security issue CVE-2020-SLCWD and guard against PATH_MAX
+      better.  Reported by Qualys.
+
+PP/04 Impose security length checks on various command-line options.
+      Fixes CVE-2020-SPRSS reported by Qualys.
+


 Exim version 4.94
 -----------------
diff --git a/src/src/acl.c b/src/src/acl.c
index a6c3d4c..f358516 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -486,7 +486,7 @@ static control_def controls_list[] = {
   { US"no_delay_flush",          FALSE,
       ACL_BIT_NOTSMTP | ACL_BIT_NOTSMTP_START
   },
-  
+
 [CONTROL_NO_ENFORCE_SYNC] =
   { US"no_enforce_sync",         FALSE,
       ACL_BIT_NOTSMTP | ACL_BIT_NOTSMTP_START
@@ -744,7 +744,7 @@ while ((s = (*func)()))
   int v, c;
   BOOL negated = FALSE;
   uschar *saveline = s;
-  uschar name[64];
+  uschar name[EXIM_DRIVERNAME_MAX];


/* Conditions (but not verbs) are allowed to be negated by an initial
exclamation mark. */
diff --git a/src/src/exim.c b/src/src/exim.c
index fd1d873..112fa4f 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -760,6 +760,25 @@ vfprintf(stderr, fmt, ap);
exit(EXIT_FAILURE);
}

+/* fail if a length is too long */
+static void
+exim_len_fail_toolong(int itemlen, int maxlen, const char *description)
+{
+if (itemlen <= maxlen)
+  return;
+fprintf(stderr, "exim: length limit exceeded (%d > %d) for: %s\n",
+        len, maxlen, description)
+exit(EXIT_FAILURE);
+}
+
+/* only pass through the string item back to the caller if it's short enough */
+static const uschar *
+exim_str_fail_toolong(const uschar *item, int maxlen, const char *description)
+{
+exim_len_fail_toolong(Ustrlen(item), maxlen, description);
+return item;
+}
+
 /* exim_chown_failure() called from exim_chown()/exim_fchown() on failure
 of chown()/fchown().  See src/functions.h for more explanation */
 int
@@ -2140,10 +2159,10 @@ on the second character (the one after '-'), to save some effort. */
         {
         if (++i >= argc)
           exim_fail("exim: string expected after %s\n", arg);
-        if (Ustrcmp(argrest, "d") == 0) ftest_domain = argv[i];
-        else if (Ustrcmp(argrest, "l") == 0) ftest_localpart = argv[i];
-        else if (Ustrcmp(argrest, "p") == 0) ftest_prefix = argv[i];
-        else if (Ustrcmp(argrest, "s") == 0) ftest_suffix = argv[i];
+        if (Ustrcmp(argrest, "d") == 0) ftest_domain = exim_str_fail_toolong(argv[i], EXIM_DOMAINNAME_MAX, "-bfd");
+        else if (Ustrcmp(argrest, "l") == 0) ftest_localpart = exim_str_fail_toolong(argv[i], EXIM_LOCALPART_MAX, "-bfl");
+        else if (Ustrcmp(argrest, "p") == 0) ftest_prefix = exim_str_fail_toolong(argv[i], EXIM_LOCALPART_MAX, "-bfp");
+        else if (Ustrcmp(argrest, "s") == 0) ftest_suffix = exim_str_fail_toolong(argv[i], EXIM_LOCALPART_MAX, "-bfs");
         else badarg = TRUE;
         }
       break;
@@ -2153,7 +2172,7 @@ on the second character (the one after '-'), to save some effort. */
       if (!*argrest || Ustrcmp(argrest, "c") == 0)
         {
         if (++i >= argc) { badarg = TRUE; break; }
-        sender_host_address = string_copy_taint(argv[i], TRUE);
+        sender_host_address = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-bh"), TRUE);
         host_checking = checking = f.log_testing_mode = TRUE;
         f.host_checking_callout = *argrest == 'c';
         message_logs = FALSE;
@@ -2611,7 +2630,7 @@ on the second character (the one after '-'), to save some effort. */
     case 'F':
     if (!*argrest)
       if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; }
-    originator_name = string_copy_taint(argrest, TRUE);
+    originator_name = string_copy_taint(exim_str_fail_toolong(argrest, EXIM_HUMANNAME_MAX, "-F"), TRUE);
     f.sender_name_forced = TRUE;
     break;


@@ -2637,6 +2656,7 @@ on the second character (the one after '-'), to save some effort. */
       uschar *errmess;
       if (!*argrest)
         if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; }
+      (void) exim_str_fail_toolong(argrest, EXIM_DISPLAYMAIL_MAX, "-f");
       if (!*argrest)
         *(sender_address = store_get(1, FALSE)) = '\0';  /* Ensure writeable memory */
       else
@@ -2733,9 +2753,9 @@ on the second character (the one after '-'), to save some effort. */
       if (msg_action_arg >= 0)
         exim_fail("exim: incompatible arguments\n");


-      continue_transport = string_copy_taint(argv[++i], TRUE);
-      continue_hostname = string_copy_taint(argv[++i], TRUE);
-      continue_host_address = string_copy_taint(argv[++i], TRUE);
+      continue_transport = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-C internal transport"), TRUE);
+      continue_hostname = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-C internal hostname"), TRUE);
+      continue_host_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-C internal hostaddr"), TRUE);
       continue_sequence = Uatoi(argv[++i]);
       msg_action = MSG_DELIVER;
       msg_action_arg = ++i;
@@ -2780,7 +2800,7 @@ on the second character (the one after '-'), to save some effort. */
     /* -MCd: for debug, set a process-purpose string */


     case 'd': if (++i < argc)
-            process_purpose = string_copy_taint(argv[i], TRUE);
+            process_purpose = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCd"), TRUE);
           else badarg = TRUE;
           break;


@@ -2788,7 +2808,7 @@ on the second character (the one after '-'), to save some effort. */
        from the commandline should be tainted - but we will need an untainted
        value for the spoolfile when doing a -odi delivery process. */


-    case 'G': if (++i < argc) queue_name = string_copy_taint(argv[i], FALSE);
+    case 'G': if (++i < argc) queue_name = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCG"), FALSE);
           else badarg = TRUE;
           break;


@@ -2861,7 +2881,7 @@ on the second character (the one after '-'), to save some effort. */
     case 'r':
     case 's': if (++i < argc)
             {
-            continue_proxy_sni = string_copy_taint(argv[i], TRUE);
+            continue_proxy_sni = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_HOSTNAME_MAX, "-MCr/-MCs"), TRUE);
             if (argrest[1] == 'r') continue_proxy_dane = TRUE;
             }
           else badarg = TRUE;
@@ -2873,13 +2893,13 @@ on the second character (the one after '-'), to save some effort. */
     and the TLS cipher. */


     case 't': if (++i < argc)
-            sending_ip_address = string_copy_taint(argv[i], TRUE);
+            sending_ip_address = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-MCt IP"), TRUE);
           else badarg = TRUE;
           if (++i < argc)
             sending_port = (int)(Uatol(argv[i]));
           else badarg = TRUE;
           if (++i < argc)
-            continue_proxy_cipher = string_copy_taint(argv[i], TRUE);
+            continue_proxy_cipher = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_CIPHERNAME_MAX, "-MCt cipher"), TRUE);
           else badarg = TRUE;
           /*FALLTHROUGH*/


@@ -2906,6 +2926,7 @@ on the second character (the one after '-'), to save some effort. */
     following options which are followed by a single message id, and which
     act on that message. Some of them use the "recipient" addresses as well.
        -Mar  add recipient(s)
+       -MG   move to a different queue
        -Mmad mark all recipients delivered
        -Mmd  mark recipients(s) delivered
        -Mes  edit sender
@@ -2941,7 +2962,7 @@ on the second character (the one after '-'), to save some effort. */
    else if (Ustrcmp(argrest, "G") == 0)
       {
       msg_action = MSG_SETQUEUE;
-      queue_name_dest = string_copy_taint(argv[++i], TRUE);
+      queue_name_dest = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-MG"), TRUE);
       }
     else if (Ustrcmp(argrest, "mad") == 0)
       {
@@ -3154,27 +3175,27 @@ on the second character (the one after '-'), to save some effort. */
     /* -oMa: Set sender host address */


     if (Ustrcmp(argrest, "a") == 0)
-      sender_host_address = string_copy_taint(argv[++i], TRUE);
+      sender_host_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMa"), TRUE);


     /* -oMaa: Set authenticator name */


     else if (Ustrcmp(argrest, "aa") == 0)
-      sender_host_authenticated = string_copy_taint(argv[++i], TRUE);
+      sender_host_authenticated = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMaa"), TRUE);


     /* -oMas: setting authenticated sender */


     else if (Ustrcmp(argrest, "as") == 0)
-      authenticated_sender = string_copy_taint(argv[++i], TRUE);
+      authenticated_sender = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"), TRUE);


     /* -oMai: setting authenticated id */


     else if (Ustrcmp(argrest, "ai") == 0)
-      authenticated_id = string_copy_taint(argv[++i], TRUE);
+      authenticated_id = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"), TRUE);


     /* -oMi: Set incoming interface address */


     else if (Ustrcmp(argrest, "i") == 0)
-      interface_address = string_copy_taint(argv[++i], TRUE);
+      interface_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMi"), TRUE);


     /* -oMm: Message reference */


@@ -3194,19 +3215,19 @@ on the second character (the one after '-'), to save some effort. */
       if (received_protocol)
         exim_fail("received_protocol is set already\n");
       else
-        received_protocol = string_copy_taint(argv[++i], TRUE);
+        received_protocol = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMr"), TRUE);


     /* -oMs: Set sender host name */


     else if (Ustrcmp(argrest, "s") == 0)
-      sender_host_name = string_copy_taint(argv[++i], TRUE);
+      sender_host_name = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-oMs"), TRUE);


     /* -oMt: Set sender ident */


     else if (Ustrcmp(argrest, "t") == 0)
       {
       sender_ident_set = TRUE;
-      sender_ident = string_copy_taint(argv[++i], TRUE);
+      sender_ident = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IDENTUSER_MAX, "-oMt"), TRUE);
       }


     /* Else a bad argument */
@@ -3256,10 +3277,11 @@ on the second character (the one after '-'), to save some effort. */
     break;


       /* -oX <list>: Override local_interfaces and/or default daemon ports */
+      /* Limits: Is there a real limit we want here?  1024 is very arbitrary. */


       case 'X':
     if (*argrest) badarg = TRUE;
-    else override_local_interfaces = string_copy_taint(argv[++i], TRUE);
+    else override_local_interfaces = string_copy_taint(exim_str_fail_toolong(argv[++i], 1024, "-oX", TRUE);
     break;


       /* -oY: Override creation of daemon notifier socket */
@@ -3307,9 +3329,10 @@ on the second character (the one after '-'), to save some effort. */
         exim_fail("received_protocol is set already\n");


       if (!hn)
-        received_protocol = string_copy_taint(argrest, TRUE);
+        received_protocol = string_copy_taint(exim_str_fail_toolong(argrest, EXIM_DRIVERNAME_MAX, "-p<protocol>"), TRUE);
       else
         {
+        (void) exim_str_fail_toolong(argrest, (EXIM_DRIVERNAME_MAX+1+EXIM_HOSTNAME_MAX), "-p<protocol>:<host>");
         received_protocol = string_copyn_taint(argrest, hn - argrest, TRUE);
         sender_host_name = string_copy_taint(hn + 1, TRUE);
         }
@@ -3365,6 +3388,7 @@ on the second character (the one after '-'), to save some effort. */
       {
       int i;
       for (argrest++, i = 0; argrest[i] && argrest[i] != '/'; ) i++;
+      exim_len_fail_toolong(i, EXIM_DRIVERNAME_MAX, "-q*G<name>");
       queue_name = string_copyn(argrest, i);
       argrest += i;
       if (*argrest == '/') argrest++;
@@ -3418,15 +3442,18 @@ on the second character (the one after '-'), to save some effort. */
     /* -R: Set string to match in addresses for forced queue run to
     pick out particular messages. */


+    /* Avoid attacks from people providing very long strings, and do so before
+    we make copies. */
+    const char *tainted_selectstr;
     if (*argrest)
-      deliver_selectstring = string_copy_taint(argrest, TRUE);
+      tainted_selectstr = argrest;
     else if (i+1 < argc)
-      deliver_selectstring = string_copy_taint(argv[++i], TRUE);
+      tainted_selectstr = argv[++i];
     else
       exim_fail("exim: string expected after -R\n");
+    deliver_selectstring = string_copy_taint(exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-R"), TRUE);
     break;


-
     /* -r: an obsolete synonym for -f (see above) */



@@ -3457,12 +3484,14 @@ on the second character (the one after '-'), to save some effort. */
     /* -S: Set string to match in addresses for forced queue run to
     pick out particular messages. */


+    const char *tainted_selectstr;
     if (*argrest)
-      deliver_selectstring_sender = string_copy_taint(argrest, TRUE);
+      tainted_selectstr = argrest;
     else if (i+1 < argc)
-      deliver_selectstring_sender = string_copy_taint(argv[++i], TRUE);
+      tainted_selectstr = argv[++i];
     else
       exim_fail("exim: string expected after -S\n");
+    deliver_selectstring_sender = string_copy_taint(exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-S"), TRUE);
     break;


     /* -Tqt is an option that is exclusively for use by the testing suite.
@@ -3544,10 +3573,12 @@ on the second character (the one after '-'), to save some effort. */
         exim_fail("exim: string expected after -X\n");
     break;


+    /* -z: a line of text to log */
+
     case 'z':
     if (!*argrest)
       if (++i < argc)
-    log_oneline = string_copy_taint(argv[i], TRUE);
+    log_oneline = string_copy_taint(exim_str_fail_toolong(argv[i], 2048, "-z logtext"), TRUE);
       else
         exim_fail("exim: file name expected after %s\n", argv[i-1]);
     break;
diff --git a/src/src/exim.h b/src/src/exim.h
index bb8e4f6..8bbeecb 100644
--- a/src/src/exim.h
+++ b/src/src/exim.h
@@ -135,6 +135,51 @@ making unique names. */
 # endif
 #endif


+/* RFC 5321 specifies that the maximum length of a local-part is 64 octets
+and the maximum length of a domain is 255 octets, but then also defines
+the maximum length of a forward/reverse path as 256 not 64+1+255.
+For an IP address, the maximum is 45 without a scope and we don't work
+with scoped addresses, so go with that.  (IPv6 with mapped IPv4).
+
+A hostname maximum length is in practice the same as the domainname, for
+the same core reasons (maximum length of a DNS name), but the semantics
+are different and seeing "DOMAIN" in source is confusing when talking about
+hostnames; so we define a second macro.  We'll use RFC 2181 as the reference
+for this one.
+
+There is no known (to me) specification on the maximum length of a human name
+in email addresses and we should be careful about imposing such a limit on
+received email, but in terms of limiting what untrusted callers specify, or
+local generation, having a limit makes sense.  Err on the side of generosity.
+
+For a display mail address, we have a human name, an email in brackets,
+possibly some (Comments), so it needs to be at least 512+3 and some more to
+avoid extraneous errors.
+Since the sane SMTP line length limit is 998, constraining such parameters to
+be 1024 seems generous and unlikely to spuriously reject legitimate
+invocations.
+
+The driver name is a name of a router/transport/authenticator etc in the
+configuration file.  We also use this for some other short strings, such
+as queue names.
+Also TLS ciphersuite name (no real known limit since the protocols use
+integers, but max seen in reality is 45 octets).
+
+RFC 1413 gives us the 512 limit on IDENT protocol userids.
+*/
+
+#define EXIM_EMAILADDR_MAX     256
+#define EXIM_LOCALPART_MAX      64
+#define EXIM_DOMAINNAME_MAX    255
+#define EXIM_IPADDR_MAX         45
+#define EXIM_HOSTNAME_MAX      255
+#define EXIM_HUMANNAME_MAX     256
+#define EXIM_DISPLAYMAIL_MAX  1024
+#define EXIM_DRIVERNAME_MAX     64
+#define EXIM_CIPHERNAME_MAX     64
+#define EXIM_IDENTUSER_MAX     512
+
+
 #include <sys/types.h>
 #include <sys/file.h>
 #include <dirent.h>
diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c
index b0f57be..5340c5a 100644
--- a/src/src/macro_predef.c
+++ b/src/src/macro_predef.c
@@ -72,7 +72,7 @@ options_from_list(optionlist * opts, unsigned nopt,
   const uschar * section, uschar * group)
 {
 const uschar * s;
-uschar buf[64];
+uschar buf[EXIM_DRIVERNAME_MAX];


/* The 'previously-defined-substring' rule for macros in config file
lines is done thus for these builtin macros: we know that the table
diff --git a/src/src/macros.h b/src/src/macros.h
index 4321780..72856a5 100644
--- a/src/src/macros.h
+++ b/src/src/macros.h
@@ -180,12 +180,6 @@ written on the spool, it gets read into big_buffer. */

#define LOCAL_SCAN_MAX_RETURN (BIG_BUFFER_SIZE - 24)

-/* A limit to the length of an address. RFC 2821 limits the local part to 64
-and the domain to 255, so this should be adequate, taking into account quotings
-etc. */
-
-#define ADDRESS_MAXLENGTH 512
-
/* The length of the base names of spool files, which consist of an internal
message id with a trailing "-H" or "-D" added. */

diff --git a/src/src/malware.c b/src/src/malware.c
index 831e9af..a6e354b 100644
--- a/src/src/malware.c
+++ b/src/src/malware.c
@@ -109,7 +109,7 @@ features_malware(void)
{
const uschar * s;
uschar * t;
-uschar buf[64];
+uschar buf[EXIM_DRIVERNAME_MAX];

spf(buf, sizeof(buf), US"_HAVE_MALWARE_");

diff --git a/src/src/parse.c b/src/src/parse.c
index 885a01c..18a6df1 100644
--- a/src/src/parse.c
+++ b/src/src/parse.c
@@ -808,11 +808,11 @@ while (isspace(endptr[-1])) endptr--;
*end = endptr - US mailbox;

/* Although this code has no limitation on the length of address extracted,
-other parts of Exim may have limits, and in any case, RFC 2821 limits local
-parts to 64 and domains to 255, so we do a check here, giving an error if the
-address is ridiculously long. */
+other parts of Exim may have limits, and in any case, RFC 5321 limits email
+addresses to 256, so we do a check here, giving an error if the address is
+ridiculously long. */

-if (*end - *start > ADDRESS_MAXLENGTH)
+if (*end - *start > EXIM_EMAILADDR_MAX)
{
*errorptr = string_sprintf("address is ridiculously long: %.64s...", yield);
return NULL;
diff --git a/src/src/readconf.c b/src/src/readconf.c
index e8e310b..8a7b710 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -422,7 +422,7 @@ options_from_list(optionlist_config, nelem(optionlist_config), US"MAIN", NULL);
void
options_auths(void)
{
-uschar buf[64];
+uschar buf[EXIM_DRIVERNAME_MAX];

options_from_list(optionlist_auths, optionlist_auths_size, US"AUTHENTICATORS", NULL);

@@ -439,7 +439,7 @@ for (struct auth_info * ai = auths_available; ai->driver_name[0]; ai++)
void
options_logging(void)
{
-uschar buf[64];
+uschar buf[EXIM_DRIVERNAME_MAX];

 for (bit_table * bp = log_options; bp < log_options + log_options_count; bp++)
   {
@@ -684,7 +684,7 @@ Returns:       FALSE iff fatal error
 BOOL
 macro_read_assignment(uschar *s)
 {
-uschar name[64];
+uschar name[EXIM_DRIVERNAME_MAX];
 int namelen = 0;
 BOOL redef = FALSE;
 macro_item *m;
@@ -1178,15 +1178,25 @@ uschar *
 readconf_readname(uschar *name, int len, uschar *s)
 {
 int p = 0;
+BOOL broken = FALSE;


 if (isalpha(Uskip_whitespace(&s)))
   while (isalnum(*s) || *s == '_')
     {
     if (p < len-1) name[p++] = *s;
+    else {
+      broken = TRUE;
+      break;
+    }
     s++;
     }


 name[p] = 0;
+if (broken) {
+  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+            "exim item name too long (>%d), unable to use \"%s\" (truncated)",
+            len, name);
+}
 Uskip_whitespace(&s);
 return s;
 }
@@ -1353,7 +1363,7 @@ static BOOL *
 get_set_flag(uschar *name, optionlist *oltop, int last, void *data_block)
 {
 optionlist *ol;
-uschar name2[64];
+uschar name2[EXIM_DRIVERNAME_MAX];
 sprintf(CS name2, "*set_%.50s", name);
 if (!(ol = find_option(name2, oltop, last)))
   log_write(0, LOG_MAIN|LOG_PANIC_DIE,
@@ -1626,8 +1636,8 @@ uschar *inttype = US"";
 uschar *sptr;
 uschar *s = buffer;
 uschar **str_target;
-uschar name[64];
-uschar name2[64];
+uschar name[EXIM_DRIVERNAME_MAX];
+uschar name2[EXIM_DRIVERNAME_MAX];


 /* There may be leading spaces; thereafter, we expect an option name starting
 with a letter. */
@@ -2089,7 +2099,7 @@ switch (type)
   case opt_bool_set:
   if (*s != 0)
     {
-    s = readconf_readname(name2, 64, s);
+    s = readconf_readname(name2, EXIM_DRIVERNAME_MAX, s);
     if (strcmpic(name2, US"true") == 0 || strcmpic(name2, US"yes") == 0)
       boolvalue = TRUE;
     else if (strcmpic(name2, US"false") == 0 || strcmpic(name2, US"no") == 0)
@@ -2436,7 +2446,7 @@ void *value;
 uid_t *uidlist;
 gid_t *gidlist;
 uschar *s;
-uschar name2[64];
+uschar name2[EXIM_DRIVERNAME_MAX];


if (!ol)
{
@@ -3706,7 +3716,7 @@ uschar *buffer;

while ((buffer = get_config_line()))
{
- uschar name[64];
+ uschar name[EXIM_DRIVERNAME_MAX];
uschar *s;

/* Read the first name on the line and test for the start of a new driver. A
@@ -4234,7 +4244,7 @@ acl_line = get_config_line();

while(acl_line)
{
- uschar name[64];
+ uschar name[EXIM_DRIVERNAME_MAX];
tree_node *node;
uschar *error;

diff --git a/src/src/transport.c b/src/src/transport.c
index d8fd858..89252ec 100644
--- a/src/src/transport.c
+++ b/src/src/transport.c
@@ -959,9 +959,10 @@ if (!(tctx->options & topt_no_headers))

   if (tctx->options & topt_add_return_path)
     {
-    uschar buffer[ADDRESS_MAXLENGTH + 20];
-    int n = sprintf(CS buffer, "Return-path: <%.*s>\n", ADDRESS_MAXLENGTH,
-      return_path);
+    uschar buffer[EXIM_EMAILADDR_MAX + 20];
+    int n = string_format(CS buffer, sizeof(buffer),
+                          "Return-path: <%.*s>\n",
+                          EXIM_EMAILADDR_MAX, return_path);
     if (!write_chunk(tctx, buffer, n)) goto bad;
     }


@@ -1729,7 +1730,7 @@ while (1)
     {
     msgq[i].bKeep = TRUE;


-    Ustrncpy_nt(msgq[i].message_id, host_record->text + (i * MESSAGE_ID_LENGTH), 
+    Ustrncpy_nt(msgq[i].message_id, host_record->text + (i * MESSAGE_ID_LENGTH),
       MESSAGE_ID_LENGTH);
     msgq[i].message_id[MESSAGE_ID_LENGTH] = 0;
     }