Make environment.c more portable
authorHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Tue, 1 Mar 2016 20:11:42 +0000 (21:11 +0100)
committerHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Tue, 1 Mar 2016 22:42:00 +0000 (23:42 +0100)
src/src/environment.c
src/src/readconf.c

index aaa84f8172a0c9c66cfec98b1444d87931867e6f..c41d19ebac552ac233738a07dcf6756075ed20f6 100644 (file)
@@ -9,6 +9,10 @@
 
 #include "exim.h"
 
+#ifndef environ
+extern char **environ;
+#endif
+
 /* The cleanup_environment() function is used during the startup phase
 of the Exim process, right after reading the configurations main
 part, before any expansions take place. It retains the environment
@@ -23,22 +27,37 @@ BOOL
 cleanup_environment()
 {
 if (!keep_environment || *keep_environment == '\0')
-  clearenv();
+  {
+  /* From: https://github.com/dovecot/core/blob/master/src/lib/env-util.c#L55
+  Try to clear the environment.
+  a) environ = NULL crashes on OS X.
+  b) *environ = NULL doesn't work on FreeBSD 7.0.
+  c) environ = emptyenv doesn't work on Haiku OS
+  d) environ = calloc() should work everywhere */
+
+  if (environ) *environ = NULL;
+
+  }
 else if (Ustrcmp(keep_environment, "*") != 0)
   {
   uschar **p;
   if (environ) for (p = USS environ; *p; /* see below */)
     {
-    uschar *name = string_copyn(*p, US Ustrchr(*p, '=') - *p);
-
-    if (OK != match_isinlist(name, CUSS &keep_environment,
-        0, NULL, NULL, MCL_NOEXPAND, FALSE, NULL))
-      if (unsetenv(CS name) < 0) return FALSE;
-      else /* nothing */;
-    else
-      p++;
+    /* It's considered broken if we do not find the '=', according to
+    Florian Weimer. For now we ignore such strings. unsetenv() would complain,
+    getenv() would complain. */
+    uschar *eqp = Ustrchr(*p, '=');
 
-    store_reset(name);
+    if (eqp)
+      {
+      uschar *name = string_copyn(*p, eqp - *p);
+      if (OK != match_isinlist(name, CUSS &keep_environment,
+          0, NULL, NULL, MCL_NOEXPAND, FALSE, NULL))
+        if (unsetenv(CS name) < 0) return FALSE;
+        else p = USS environ; /* RESTART from the beginning */
+      else p++;
+      store_reset(name);
+      }
     }
   }
 if (add_environment)
index cf5f069e90b418a65a776002b8547e4d5d1ca8a2..92160c8f28dc41cbf71d6de33b55cb9218a4d507 100644 (file)
@@ -15,6 +15,13 @@ static void fn_smtp_receive_timeout(const uschar * name, const uschar * str);
 static void save_config_line(const uschar* line);
 static void save_config_position(const uschar *file, int line);
 static void print_config(BOOL admin);
+/* glibc seems to define environ as a macro, we can use this to check
+it's existence. And, if we declare environ a 2nd time, it shouldn't
+harm */
+#ifndef environ
+extern char **environ;
+#endif
+
 
 #define CSTATE_STACK_SIZE 10