Docs: clarify $authentication_failed. Bug 2878
[exim.git] / src / src / readconf.c
index 34ebf87690777ce927f7a0ff37bc6f5e3c77e09d..06bc50fd88a5e8e946c5b1a10cc87bf3f9c25d6f 100644 (file)
@@ -2,8 +2,8 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions for reading the configuration file, and for displaying
@@ -68,9 +68,6 @@ static optionlist optionlist_config[] = {
   { "add_environment",          opt_stringptr,   {&add_environment} },
   { "admin_groups",             opt_gidlist,     {&admin_groups} },
   { "allow_domain_literals",    opt_bool,        {&allow_domain_literals} },
-#ifdef ALLOW_INSECURE_TAINTED_DATA
-  { "allow_insecure_tainted_data", opt_bool,     {&allow_insecure_tainted_data} },
-#endif
   { "allow_mx_to_ip",           opt_bool,        {&allow_mx_to_ip} },
   { "allow_utf8_domains",       opt_bool,        {&allow_utf8_domains} },
   { "auth_advertise_hosts",     opt_stringptr,   {&auth_advertise_hosts} },
@@ -183,6 +180,9 @@ static optionlist optionlist_config[] = {
   { "hosts_connection_nolog",   opt_stringptr,   {&hosts_connection_nolog} },
 #ifdef SUPPORT_PROXY
   { "hosts_proxy",              opt_stringptr,   {&hosts_proxy} },
+#endif
+#ifndef DISABLE_TLS
+  { "hosts_require_alpn",       opt_stringptr,   {&hosts_require_alpn} },
 #endif
   { "hosts_require_helo",       opt_stringptr,   {&hosts_require_helo} },
   { "hosts_treat_as_local",     opt_stringptr,   {&hosts_treat_as_local} },
@@ -345,15 +345,6 @@ static optionlist optionlist_config[] = {
 #ifdef LOOKUP_SQLITE
   { "sqlite_dbfile",            opt_stringptr,   {&sqlite_dbfile} },
   { "sqlite_lock_timeout",      opt_int,         {&sqlite_lock_timeout} },
-#endif
-#ifdef EXPERIMENTAL_SRS_ALT
-  { "srs_config",               opt_stringptr,   {&srs_config} },
-  { "srs_hashlength",           opt_int,         {&srs_hashlength} },
-  { "srs_hashmin",              opt_int,         {&srs_hashmin} },
-  { "srs_maxage",               opt_int,         {&srs_maxage} },
-  { "srs_secrets",              opt_stringptr,   {&srs_secrets} },
-  { "srs_usehash",              opt_bool,        {&srs_usehash} },
-  { "srs_usetimestamp",         opt_bool,        {&srs_usetimestamp} },
 #endif
   { "strict_acl_vars",          opt_bool,        {&strict_acl_vars} },
   { "strip_excess_angle_brackets", opt_bool,     {&strip_excess_angle_brackets} },
@@ -378,6 +369,7 @@ static optionlist optionlist_config[] = {
   { "timezone",                 opt_stringptr,   {&timezone_string} },
   { "tls_advertise_hosts",      opt_stringptr,   {&tls_advertise_hosts} },
 #ifndef DISABLE_TLS
+  { "tls_alpn",                        opt_stringptr,   {&tls_alpn} },
   { "tls_certificate",          opt_stringptr,   {&tls_certificate} },
   { "tls_crl",                  opt_stringptr,   {&tls_crl} },
   { "tls_dh_max_bits",          opt_int,         {&tls_dh_max_bits} },
@@ -654,7 +646,7 @@ Args:
 macro_item *
 macro_create(const uschar * name, const uschar * val, BOOL command_line)
 {
-macro_item * m = store_get(sizeof(macro_item), FALSE);
+macro_item * m = store_get(sizeof(macro_item), GET_UNTAINTED);
 
 READCONF_DEBUG fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val);
 m->next = NULL;
@@ -1084,7 +1076,7 @@ for (;;)
 
     if (config_lines)
       save_config_position(config_filename, config_lineno);
-    save = store_get(sizeof(config_file_item), FALSE);
+    save = store_get(sizeof(config_file_item), GET_UNTAINTED);
     save->next = config_file_stack;
     config_file_stack = save;
     save->file = config_file;
@@ -1433,7 +1425,7 @@ Returns:      the control block for the parsed rule.
 static rewrite_rule *
 readconf_one_rewrite(const uschar *p, int *existflags, BOOL isglobal)
 {
-rewrite_rule *next = store_get(sizeof(rewrite_rule), FALSE);
+rewrite_rule * next = store_get(sizeof(rewrite_rule), GET_UNTAINTED);
 
 next->next = NULL;
 next->key = string_dequote(&p);
@@ -3011,7 +3003,7 @@ read_named_list(tree_node **anchorp, int *numberp, int max, uschar *s,
 BOOL forcecache = FALSE;
 uschar *ss;
 tree_node *t;
-namedlist_block * nb = store_get(sizeof(namedlist_block), FALSE);
+namedlist_block * nb = store_get_perm(sizeof(namedlist_block), FALSE);
 
 if (Ustrncmp(s, "_cache", 6) == 0)
   {
@@ -3029,7 +3021,7 @@ if (*numberp >= max)
 Uskip_whitespace(&s);
 ss = s;
 while (isalnum(*s) || *s == '_') s++;
-t = store_get(sizeof(tree_node) + s-ss, is_tainted(ss));
+t = store_get(sizeof(tree_node) + s-ss, ss);
 Ustrncpy(t->name, ss, s-ss);
 t->name[s-ss] = 0;
 Uskip_whitespace(&s);
@@ -3142,55 +3134,54 @@ while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
 
   /* Cut out all the fancy processing unless specifically wanted */
 
-  #if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
+#if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
   uschar *suffix = filename + Ustrlen(filename);
 
   /* Try for the node-specific file if a node name exists */
 
-  #ifdef CONFIGURE_FILE_USE_NODE
+ifdef CONFIGURE_FILE_USE_NODE
   struct utsname uts;
   if (uname(&uts) >= 0)
     {
-    #ifdef CONFIGURE_FILE_USE_EUID
+#  ifdef CONFIGURE_FILE_USE_EUID
     sprintf(CS suffix, ".%ld.%.256s", (long int)original_euid, uts.nodename);
-    config_file = Ufopen(filename, "rb");
-    if (config_file == NULL)
-    #endif  /* CONFIGURE_FILE_USE_EUID */
+    if (!(config_file = Ufopen(filename, "rb")))
+#  endif  /* CONFIGURE_FILE_USE_EUID */
       {
       sprintf(CS suffix, ".%.256s", uts.nodename);
       config_file = Ufopen(filename, "rb");
       }
     }
-  #endif  /* CONFIGURE_FILE_USE_NODE */
+endif  /* CONFIGURE_FILE_USE_NODE */
 
   /* Otherwise, try the generic name, possibly with the euid added */
 
-  #ifdef CONFIGURE_FILE_USE_EUID
-  if (config_file == NULL)
+ifdef CONFIGURE_FILE_USE_EUID
+  if (!config_file)
     {
     sprintf(CS suffix, ".%ld", (long int)original_euid);
     config_file = Ufopen(filename, "rb");
     }
-  #endif  /* CONFIGURE_FILE_USE_EUID */
+endif  /* CONFIGURE_FILE_USE_EUID */
 
   /* Finally, try the unadorned name */
 
-  if (config_file == NULL)
+  if (!config_file)
     {
     *suffix = 0;
     config_file = Ufopen(filename, "rb");
     }
-  #else  /* if neither defined */
+#else  /* if neither defined */
 
   /* This is the common case when the fancy processing is not included. */
 
   config_file = Ufopen(filename, "rb");
-  #endif
+#endif
 
   /* If the file does not exist, continue to try any others. For any other
   error, break out (and die). */
 
-  if (config_file != NULL || errno != ENOENT) break;
+  if (config_file || errno != ENOENT) break;
   }
 
 /* On success, save the name for verification; config_filename is used when
@@ -3213,39 +3204,37 @@ if (config_file)
     config_main_directory = last_slash == filename ? US"/" : string_copyn(filename, last_slash - filename);
   else
     {
-      /* relative configuration file name: working dir + / + basename(filename) */
+    /* relative configuration file name: working dir + / + basename(filename) */
 
-      uschar buf[PATH_MAX];
-      gstring * g;
+    uschar buf[PATH_MAX];
+    gstring * g;
 
-      if (os_getcwd(buf, PATH_MAX) == NULL)
-        {
-        perror("exim: getcwd");
-        exit(EXIT_FAILURE);
-        }
-      g = string_cat(NULL, buf);
+    if (os_getcwd(buf, PATH_MAX) == NULL)
+      {
+      perror("exim: getcwd");
+      exit(EXIT_FAILURE);
+      }
+    g = string_cat(NULL, buf);
 
-      /* If the dir does not end with a "/", append one */
-      if (g->s[g->ptr-1] != '/')
-        g = string_catn(g, US"/", 1);
+    /* If the dir does not end with a "/", append one */
+    if (g->s[g->ptr-1] != '/')
+      g = string_catn(g, US"/", 1);
 
-      /* If the config file contains a "/", extract the directory part */
-      if (last_slash)
-        g = string_catn(g, filename, last_slash - filename);
+    /* If the config file contains a "/", extract the directory part */
+    if (last_slash)
+      g = string_catn(g, filename, last_slash - filename);
 
-      config_main_directory = string_from_gstring(g);
+    config_main_directory = string_from_gstring(g);
     }
   config_directory = config_main_directory;
   }
 else
-  {
   if (!filename)
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "non-existent configuration file(s): "
       "%s", config_main_filelist);
   else
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
       string_open_failed("configuration file %s", filename));
-  }
 
 /* Now, once we found and opened our configuration file, we change the directory
 to a safe place. Later we change to $spool_directory. */
@@ -3265,19 +3254,19 @@ if (f.trusted_config && Ustrcmp(filename, US"/dev/null"))
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to stat configuration file %s",
       big_buffer);
 
-  if ((statbuf.st_uid != root_uid                /* owner not root */
-       #ifdef CONFIGURE_OWNER
-       && statbuf.st_uid != config_uid           /* owner not the special one */
-       #endif
-         ) ||                                    /* or */
-      (statbuf.st_gid != root_gid                /* group not root & */
-       #ifdef CONFIGURE_GROUP
-       && statbuf.st_gid != config_gid           /* group not the special one */
-       #endif
-       && (statbuf.st_mode & 020) != 0) ||       /* group writeable  */
-                                                 /* or */
-      ((statbuf.st_mode & 2) != 0))              /* world writeable  */
-
+  if (    statbuf.st_uid != root_uid           /* owner not root */
+#ifdef CONFIGURE_OWNER
+       && statbuf.st_uid != config_uid         /* owner not the special one */
+#endif
+     ||                                                /* or */
+         statbuf.st_gid != root_gid            /* group not root & */
+#ifdef CONFIGURE_GROUP
+       && statbuf.st_gid != config_gid         /* group not the special one */
+#endif
+       && (statbuf.st_mode & 020) != 0         /* group writeable  */
+     ||                                                /* or */
+       (statbuf.st_mode & 2) != 0              /* world writeable  */
+     )
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Exim configuration file %s has the "
       "wrong owner, group, or mode", big_buffer);
 
@@ -3290,7 +3279,7 @@ if (f.trusted_config && Ustrcmp(filename, US"/dev/null"))
   if (statbuf.st_size > 8192)
     {
     rmark r = store_mark();
-    void * dummy = store_get((int)statbuf.st_size, FALSE);
+    void * dummy = store_get((int)statbuf.st_size, GET_UNTAINTED);
     store_reset(r);
     }
   }
@@ -3324,11 +3313,11 @@ while ((s = get_config_line()))
     read_named_list(&hostlist_anchor, &hostlist_count,
       MAX_NAMED_LIST, t+8, US"host list", hide);
 
-  else if (Ustrncmp(t, US"addresslist", 11) == 0)
+  else if (Ustrncmp(t, "addresslist", 11) == 0)
     read_named_list(&addresslist_anchor, &addresslist_count,
       MAX_NAMED_LIST, t+11, US"address list", hide);
 
-  else if (Ustrncmp(t, US"localpartlist", 13) == 0)
+  else if (Ustrncmp(t, "localpartlist", 13) == 0)
     read_named_list(&localpartlist_anchor, &localpartlist_count,
       MAX_NAMED_LIST, t+13, US"local part list", hide);
 
@@ -3347,7 +3336,7 @@ if (local_sender_retain && local_from_check)
 /* If the timezone string is empty, set it to NULL, implying no TZ variable
 wanted. */
 
-if (timezone_string != NULL && *timezone_string == 0) timezone_string = NULL;
+if (timezone_string && !*timezone_string) timezone_string = NULL;
 
 /* The max retry interval must not be greater than 24 hours. */
 
@@ -3492,7 +3481,7 @@ if (syslog_facility_str)
 
 /* Expand pid_file_path */
 
-if (*pid_file_path != 0)
+if (*pid_file_path)
   {
   if (!(s = expand_string(pid_file_path)))
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand pid_file_path "
@@ -3502,7 +3491,7 @@ if (*pid_file_path != 0)
 
 /* Set default value of process_log_path */
 
-if (!process_log_path || *process_log_path =='\0')
+if (!process_log_path || !*process_log_path)
   process_log_path = string_sprintf("%s/exim-process.info", spool_directory);
 
 /* Compile the regex for matching a UUCP-style "From_" line in an incoming
@@ -3554,7 +3543,7 @@ if (errors_reply_to)
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
       "error in errors_reply_to (%s): %s", errors_reply_to, errmess);
 
-  if (domain == 0)
+  if (!domain)
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
       "errors_reply_to (%s) does not contain a domain", errors_reply_to);
   }
@@ -3562,8 +3551,7 @@ if (errors_reply_to)
 /* If smtp_accept_queue or smtp_accept_max_per_host is set, then
 smtp_accept_max must also be set. */
 
-if (smtp_accept_max == 0 &&
-    (smtp_accept_queue > 0 || smtp_accept_max_per_host != NULL))
+if (smtp_accept_max == 0 && (smtp_accept_queue > 0 || smtp_accept_max_per_host))
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
     "smtp_accept_max must be set if smtp_accept_queue or "
     "smtp_accept_max_per_host is set");
@@ -3584,7 +3572,7 @@ if (host_number_string)
         host_number_string, expand_string_message);
   n = Ustrtol(s, &end, 0);
   while (isspace(*end)) end++;
-  if (*end != 0)
+  if (*end)
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
       "localhost_number value is not a number: %s", s);
   if (n > LOCALHOST_MAX)
@@ -3661,7 +3649,7 @@ for (driver_info * dd = drivers_available; dd->driver_name[0] != 0;
     {
     int len = dd->options_len;
     d->info = dd;
-    d->options_block = store_get(len, FALSE);
+    d->options_block = store_get_perm(len, FALSE);
     memcpy(d->options_block, dd->options_block, len);
     for (int i = 0; i < *(dd->options_count); i++)
       dd->options[i].type &= ~opt_set;
@@ -3677,6 +3665,16 @@ return NULL;   /* never obeyed */
 
 
 
+static void
+driver_init_fini(driver_instance * d, const uschar * class)
+{
+if (!d->driver_name)
+  log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+    "no driver defined for %s \"%s\"", class, d->name);
+(d->info->init)(d);
+}
+
+
 /*************************************************
 *             Initialize driver list             *
 *************************************************/
@@ -3737,11 +3735,8 @@ while ((buffer = get_config_line()))
     {
     if (d)
       {
-      if (!d->driver_name)
-        log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
-          "no driver defined for %s \"%s\"", class, d->name);
       /* s is using big_buffer, so this call had better not */
-      (d->info->init)(d);
+      driver_init_fini(d, class);
       d = NULL;
       }
     if (!macro_read_assignment(buffer)) exim_exit(EXIT_FAILURE);
@@ -3757,12 +3752,7 @@ while ((buffer = get_config_line()))
     /* Finish off initializing the previous driver. */
 
     if (d)
-      {
-      if (!d->driver_name)
-        log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
-          "no driver defined for %s \"%s\"", class, d->name);
-      (d->info->init)(d);
-      }
+      driver_init_fini(d, class);
 
     /* Check that we haven't already got a driver of this name */
 
@@ -3774,11 +3764,13 @@ while ((buffer = get_config_line()))
     /* Set up a new driver instance data block on the chain, with
     its default values installed. */
 
-    d = store_get(instance_size, FALSE);
+    d = store_get_perm(instance_size, FALSE);
     memcpy(d, instance_default, instance_size);
     *p = d;
     p = &d->next;
     d->name = string_copy(name);
+    d->srcfile = config_filename;
+    d->srcline = config_lineno; 
 
     /* Clear out the "set" bits in the generic options */
 
@@ -3826,12 +3818,7 @@ while ((buffer = get_config_line()))
 /* Run the initialization function for the final driver. */
 
 if (d)
-  {
-  if (!d->driver_name)
-    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
-      "no driver defined for %s \"%s\"", class, d->name);
-  (d->info->init)(d);
-  }
+  driver_init_fini(d, class);
 }
 
 
@@ -4071,7 +4058,7 @@ while ((p = get_config_line()))
   const uschar *pp;
   uschar *error;
 
-  next = store_get(sizeof(retry_config), FALSE);
+  next = store_get(sizeof(retry_config), GET_UNTAINTED);
   next->next = NULL;
   *chain = next;
   chain = &(next->next);
@@ -4115,7 +4102,7 @@ while ((p = get_config_line()))
 
   while (*p)
     {
-    retry_rule *rule = store_get(sizeof(retry_rule), FALSE);
+    retry_rule * rule = store_get(sizeof(retry_rule), GET_UNTAINTED);
     *rchain = rule;
     rchain = &(rule->next);
     rule->next = NULL;
@@ -4193,11 +4180,12 @@ for (auth_instance * au = auths; au; au = au->next)
 
   for (auth_instance * bu = au->next; bu; bu = bu->next)
     if (strcmpic(au->public_name, bu->public_name) == 0)
-      if ((au->client && bu->client) || (au->server && bu->server))
+      if (  au->client && bu->client
+        || au->server && bu->server)
         log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "two %s authenticators "
           "(%s and %s) have the same public name (%s)",
-          au->client ? US"client" : US"server", au->name, bu->name,
-          au->public_name);
+          au->client && bu->client ? US"client" : US"server",
+         au->name, bu->name, au->public_name);
 #ifndef DISABLE_PIPE_CONNECT
   nauths++;
 #endif
@@ -4208,6 +4196,18 @@ f.smtp_in_early_pipe_no_auth = nauths > 16;
 }
 
 
+/* For error messages, a string describing the config location associated
+with current processing.  NULL if we are not in an authenticator. */
+
+uschar *
+authenticator_current_name(void)
+{
+if (!authenticator_name) return NULL;
+return string_sprintf(" (authenticator %s, %s %d)", authenticator_name, driver_srcfile, driver_srcline);
+}
+
+
+
 
 
 /*************************************************
@@ -4264,7 +4264,7 @@ while(acl_line)
   if (*p != ':' || name[0] == 0)
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "missing or malformed ACL name");
 
-  node = store_get(sizeof(tree_node) + Ustrlen(name), is_tainted(name));
+  node = store_get_perm(sizeof(tree_node) + Ustrlen(name), name);
   Ustrcpy(node->name, name);
   if (!tree_insertnode(&acl_anchor, node))
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
@@ -4409,7 +4409,7 @@ save_config_line(const uschar* line)
 static config_line_item *current;
 config_line_item *next;
 
-next = (config_line_item*) store_get(sizeof(config_line_item), FALSE);
+next = (config_line_item*) store_get(sizeof(config_line_item), GET_UNTAINTED);
 next->line = string_copy(line);
 next->next = NULL;
 
@@ -4426,25 +4426,28 @@ print_config(BOOL admin, BOOL terse)
 {
 const int TS = terse ? 0 : 2;
 int indent = 0;
+rmark r = NULL;
 
-for (config_line_item * i = config_lines; i; i = i->next)
+for (const config_line_item * i = config_lines; i; i = i->next)
   {
-  uschar *current;
-  uschar *p;
+  uschar * current, * p;
+
+  if (r) store_reset(r);
+  r = store_mark();
 
   /* skip over to the first non-space */
-  for (current = i->line; *current && isspace(*current); ++current)
+  for (current = string_copy(i->line); *current && isspace(*current); ++current)
     ;
 
-  if (*current == '\0')
+  if (!*current)
     continue;
 
   /* Collapse runs of spaces. We stop this if we encounter one of the
-   * following characters: "'$, as this may indicate careful formatting */
-  for (p = current; *p; ++p)
+  following characters: "'$, as this may indicate careful formatting */
+
+  for (p = current; *p; p++) if (isspace(*p))
     {
     uschar *next;
-    if (!isspace(*p)) continue;
     if (*p != ' ') *p = ' ';
 
     for (next = p; isspace(*next); ++next)
@@ -4498,6 +4501,7 @@ for (config_line_item * i = config_lines; i; i = i->next)
     /* rest is public */
     printf("%*s%s\n", indent, "", current);
   }
+if (r) store_reset(r);
 }
 
 #endif /*!MACRO_PREDEF*/