Allow Routers to have multiple conditions, IF each one yields a strict bool.
[exim.git] / src / src / readconf.c
index 2e65cd970fa257332f228944bf560c33f74aaba0..6fd0dd8ea975095d234aec2be9ebfad69ba293a3 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/readconf.c,v 1.35 2008/02/12 12:52:51 nm4 Exp $ */
+/* $Cambridge: exim/src/src/readconf.c,v 1.42 2010/06/07 07:09:10 pdp Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2007 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions for reading the configuration file, and for displaying
@@ -142,6 +142,9 @@ static optionlist optionlist_config[] = {
   { "acl_smtp_auth",            opt_stringptr,   &acl_smtp_auth },
   { "acl_smtp_connect",         opt_stringptr,   &acl_smtp_connect },
   { "acl_smtp_data",            opt_stringptr,   &acl_smtp_data },
+#ifndef DISABLE_DKIM
+  { "acl_smtp_dkim",            opt_stringptr,   &acl_smtp_dkim },
+#endif
   { "acl_smtp_etrn",            opt_stringptr,   &acl_smtp_etrn },
   { "acl_smtp_expn",            opt_stringptr,   &acl_smtp_expn },
   { "acl_smtp_helo",            opt_stringptr,   &acl_smtp_helo },
@@ -205,6 +208,9 @@ static optionlist optionlist_config[] = {
   { "disable_fsync",            opt_bool,        &disable_fsync },
 #endif
   { "disable_ipv6",             opt_bool,        &disable_ipv6 },
+#ifndef DISABLE_DKIM
+  { "dkim_verify_signers",      opt_stringptr,   &dkim_verify_signers },
+#endif
   { "dns_again_means_nonexist", opt_stringptr,   &dns_again_means_nonexist },
   { "dns_check_names_pattern",  opt_stringptr,   &check_dns_names_pattern },
   { "dns_csa_search_limit",     opt_int,         &dns_csa_search_limit },
@@ -229,6 +235,7 @@ static optionlist optionlist_config[] = {
   { "gecos_name",               opt_stringptr,   &gecos_name },
   { "gecos_pattern",            opt_stringptr,   &gecos_pattern },
 #ifdef SUPPORT_TLS
+  { "gnutls_compat_mode",       opt_bool,        &gnutls_compat_mode },
   { "gnutls_require_kx",        opt_stringptr,   &gnutls_require_kx },
   { "gnutls_require_mac",       opt_stringptr,   &gnutls_require_mac },
   { "gnutls_require_protocols", opt_stringptr,   &gnutls_require_proto },
@@ -284,6 +291,9 @@ static optionlist optionlist_config[] = {
   { "mysql_servers",            opt_stringptr,   &mysql_servers },
 #endif
   { "never_users",              opt_uidlist,     &never_users },
+#ifdef SUPPORT_TLS
+  { "openssl_options",          opt_stringptr,   &openssl_options },
+#endif
 #ifdef LOOKUP_ORACLE
   { "oracle_servers",           opt_stringptr,   &oracle_servers },
 #endif
@@ -1348,6 +1358,7 @@ uid_t uid;
 gid_t gid;
 BOOL boolvalue = TRUE;
 BOOL freesptr = TRUE;
+BOOL extra_condition = FALSE;
 optionlist *ol, *ol2;
 struct passwd *pw;
 void *reset_point;
@@ -1355,6 +1366,8 @@ int intbase = 0;
 uschar *inttype = US"";
 uschar *sptr;
 uschar *s = buffer;
+uschar *saved_condition, *strtemp;
+uschar **str_target;
 uschar name[64];
 uschar name2[64];
 
@@ -1412,8 +1425,11 @@ if ((ol->type & opt_set) != 0)
   {
   uschar *mname = name;
   if (Ustrncmp(mname, "no_", 3) == 0) mname += 3;
-  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
-    "\"%s\" option set for the second time", mname);
+  if (Ustrcmp(mname, "condition") == 0)
+    extra_condition = TRUE;
+  else
+    log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+      "\"%s\" option set for the second time", mname);
   }
 
 ol->type |= opt_set | issecure;
@@ -1494,6 +1510,26 @@ switch (type)
     control block and flags word. */
 
     case opt_stringptr:
+    if (data_block == NULL)
+      str_target = (uschar **)(ol->value);
+    else
+      str_target = (uschar **)((uschar *)data_block + (long int)(ol->value));
+    if (extra_condition)
+      {
+      /* We already have a condition, we're conducting a crude hack to let multiple
+      condition rules be chained together, despite storing them in text form. */
+      saved_condition = *str_target;
+      strtemp = string_sprintf("${if and{{bool{%s}}{bool{%s}}}}",
+          saved_condition, sptr);
+      *str_target = string_copy_malloc(strtemp);
+      }
+    else
+      {
+      *str_target = sptr;
+      freesptr = FALSE;
+      }
+    break;
+
     case opt_rewrite:
     if (data_block == NULL)
       *((uschar **)(ol->value)) = sptr;
@@ -2360,15 +2396,17 @@ second argument is NULL. There are some special values:
   routers            print the routers' configurations
   transports         print the transports' configuration
   authenticators     print the authenticators' configuration
+  macros             print the macros' configuration
   router_list        print a list of router names
   transport_list     print a list of transport names
   authenticator_list print a list of authentication mechanism names
+  macro_list         print a list of macro names
   +name              print a named list item
   local_scan         print the local_scan options
 
-If the second argument is not NULL, it must be one of "router", "transport", or
-"authenticator" in which case the first argument identifies the driver whose
-options are to be printed.
+If the second argument is not NULL, it must be one of "router", "transport",
+"authenticator" or "macro" in which case the first argument identifies the
+driver whose options are to be printed.
 
 Arguments:
   name        option name if type == NULL; else driver name
@@ -2384,6 +2422,7 @@ BOOL names_only = FALSE;
 optionlist *ol;
 optionlist *ol2 = NULL;
 driver_instance *d = NULL;
+macro_item *m;
 int size = 0;
 
 if (type == NULL)
@@ -2465,11 +2504,10 @@ if (type == NULL)
     name = NULL;
     }
 
-  else if (Ustrcmp(name, "authenticator_list") == 0)
+  else if (Ustrcmp(name, "macros") == 0)
     {
-    type = US"authenticator";
+    type = US"macro";
     name = NULL;
-    names_only = TRUE;
     }
 
   else if (Ustrcmp(name, "router_list") == 0)
@@ -2478,12 +2516,28 @@ if (type == NULL)
     name = NULL;
     names_only = TRUE;
     }
+
   else if (Ustrcmp(name, "transport_list") == 0)
     {
     type = US"transport";
     name = NULL;
     names_only = TRUE;
     }
+
+  else if (Ustrcmp(name, "authenticator_list") == 0)
+    {
+    type = US"authenticator";
+    name = NULL;
+    names_only = TRUE;
+    }
+
+  else if (Ustrcmp(name, "macro_list") == 0)
+    {
+    type = US"macro";
+    name = NULL;
+    names_only = TRUE;
+    }
+
   else
     {
     print_ol(find_option(name, optionlist_config, optionlist_config_size),
@@ -2517,6 +2571,32 @@ else if (Ustrcmp(type, "authenticator") == 0)
   size = optionlist_auths_size;
   }
 
+else if (Ustrcmp(type, "macro") == 0)
+  {
+  /* People store passwords in macros and they were previously not available
+  for printing.  So we have an admin_users restriction. */
+  if (!admin_user)
+    {
+    fprintf(stderr, "exim: permission denied\n");
+    exit(EXIT_FAILURE);
+    }
+  for (m = macros; m != NULL; m = m->next)
+    {
+    if (name == NULL || Ustrcmp(name, m->name) == 0)
+      {
+      if (names_only)
+        printf("%s\n", CS m->name);
+      else
+        printf("%s=%s\n", CS m->name, CS m->replacement);
+      if (name != NULL)
+        return;
+      }
+    }
+  if (name != NULL)
+    printf("%s %s not found\n", type, name);
+  return;
+  }
+
 if (names_only)
   {
   for (; d != NULL; d = d->next) printf("%s\n", CS d->name);
@@ -3105,6 +3185,20 @@ if ((tls_verify_hosts != NULL || tls_try_verify_hosts != NULL) &&
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
     "tls_%sverify_hosts is set, but tls_verify_certificates is not set",
     (tls_verify_hosts != NULL)? "" : "try_");
+
+/* If openssl_options is set, validate it */
+if (openssl_options != NULL)
+  {
+# ifdef USE_GNUTLS
+  log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+    "openssl_options is set but we're using GnuTLS\n");
+# else
+  long dummy;
+  if (!(tls_openssl_options_parse(openssl_options, &dummy)))
+    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+      "openssl_options parse error: %s\n", openssl_options);
+# endif
+  }
 #endif
 }