For the new SIZE_T_FMT, if not C99 then our size_t conversion specifier
[exim.git] / src / src / buildconfig.c
index 6dd0d51120ebcb49038a897cee2b01e060a80d3c..3cd9b2924d5fbdfa03be3b4fc8a538bdda1d827d 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/buildconfig.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */
+/* $Cambridge: exim/src/src/buildconfig.c,v 1.18 2010/06/07 18:09:07 pdp Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2004 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
 /* This auxiliary program builds the file config.h by the following
 process:
 
-First it reads Makefile, looking for certain OS-specific definitions which it
-uses to define macros. Then it reads the defaults file config.h.defaults.
+First, it determines the size of off_t and time_t variables, and generates
+macro code to define OFF_T_FMT and TIME_T_FMT as suitable formats, if they are
+not already defined in the system-specific header file.
+
+Then it reads Makefile, looking for certain OS-specific definitions which it
+uses to define some specific macros. Finally, it reads the defaults file
+config.h.defaults.
 
 The defaults file contains normal C #define statements for various macros; if
 the name of a macro is found in the environment, the environment value replaces
@@ -29,6 +34,7 @@ normally called independently. */
 
 
 #include <ctype.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -96,6 +102,13 @@ if (!OK)
 int
 main(int argc, char **argv)
 {
+off_t test_off_t = 0;
+time_t test_time_t = 0;
+#if !(__STDC_VERSION__ >= 199901L) && !defined(PRIdMAX)
+size_t test_size_t = 0;
+unsigned long test_ulong_t = 0L;
+#endif
+long test_long_t = 0;
 FILE *base;
 FILE *new;
 int last_initial = 'A';
@@ -132,13 +145,65 @@ fprintf(new, "using values specified in the configuration file Local/Makefile.\n
 fprintf(new, "Do not edit it. Instead, edit Local/Makefile and "
   "rerun make. */\n\n");
 
-/* First, search the makefile for certain settings */
+/* First, deal with the printing format for off_t variables. We assume that if
+the size of off_t is greater than 4, "%lld" will be available as a format for
+printing long long variables, and there will be support for the long long type.
+This assumption is known to be OK for the common operating systems. */
+
+fprintf(new, "#ifndef OFF_T_FMT\n");
+if (sizeof(test_off_t) > sizeof(test_long_t))
+  {
+  fprintf(new, "#define OFF_T_FMT  \"%%lld\"\n");
+  fprintf(new, "#define LONGLONG_T long long int\n");
+  }
+else
+  {
+  fprintf(new, "#define OFF_T_FMT  \"%%ld\"\n");
+  fprintf(new, "#define LONGLONG_T long int\n");
+  }
+fprintf(new, "#endif\n\n");
+
+/* Now do the same thing for time_t variables. If the length is greater than
+4, we want to assume long long support (even if off_t was less than 4). If the
+length is 4 or less, we can leave LONGLONG_T to whatever was defined above for
+off_t. */
+
+fprintf(new, "#ifndef TIME_T_FMT\n");
+if (sizeof(test_time_t) > sizeof(test_long_t))
+  {
+  fprintf(new, "#define TIME_T_FMT  \"%%lld\"\n");
+  fprintf(new, "#undef  LONGLONG_T\n");
+  fprintf(new, "#define LONGLONG_T long long int\n");
+  }
+else
+  {
+  fprintf(new, "#define TIME_T_FMT  \"%%ld\"\n");
+  }
+fprintf(new, "#endif\n\n");
+
+/* And for sizeof() results, size_t, which should with C99 be just %zu, deal
+with C99 not being ubiquitous yet.  Unfortunately. */
+
+#if __STDC_VERSION__ >= 199901L
+fprintf(new, "#define SIZE_T_FMT  \"%%zu\"\n");
+#else
+# ifdef PRIdMAX
+fprintf(new, "#define SIZE_T_FMT  \"%%" PRIdMAX "\"\n");
+# else
+if (sizeof(test_size_t) > sizeof (test_ulong_t))
+  fprintf(new, "#define SIZE_T_FMT  \"%%llu\"\n");
+else
+  fprintf(new, "#define SIZE_T_FMT  \"%%lu\"\n");
+# endif
+#endif
+
+/* Now search the makefile for certain settings */
 
 base = fopen("Makefile", "rb");
 if (base == NULL)
   {
   printf("*** Buildconfig: failed to open Makefile\n");
-  fclose(new);
+  (void)fclose(new);
   exit(1);
   }
 
@@ -242,15 +307,16 @@ fprintf(new, "#define HAVE_ICONV            %s\n",
 if (errno_quota[0] != 0)
   fprintf(new, "\n#define ERRNO_QUOTA           %s\n", errno_quota);
 
-if (strcmp(cc, "gcc") == 0 && strstr(ostype, "IRIX") != NULL)
+if (strcmp(cc, "gcc") == 0 &&
+    (strstr(ostype, "IRIX") != NULL || strstr(ostype, "AIX") != NULL))
   {
   fprintf(new, "\n/* This switch includes the code to fix the inet_ntoa() */");
-  fprintf(new, "\n/* bug when using gcc on an IRIX system. */");
+  fprintf(new, "\n/* bug when using gcc on an IRIX or AIX system. */");
   fprintf(new, "\n#define USE_INET_NTOA_FIX");
   }
 
 fprintf(new, "\n");
-fclose(base);
+(void)fclose(base);
 
 
 /* Now handle the macros listed in the defaults */
@@ -259,7 +325,7 @@ base = fopen("../src/config.h.defaults", "rb");
 if (base == NULL)
   {
   printf("*** Buildconfig: failed to open ../src/config.h.defaults\n");
-  fclose(new);
+  (void)fclose(new);
   exit(1);
   }
 
@@ -312,6 +378,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
     uid_t uid = 0;
     gid_t gid = 0;
     int gid_set = 0;
+    int uid_not_set = 0;
     char *username = NULL;
     char *groupname = NULL;
     char *s;
@@ -366,6 +433,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
       while (isspace(*user)) user++;
       username = user;
       gid_set = 1;
+      uid_not_set = 1;
       }
 
     else
@@ -459,6 +527,18 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
       return 1;
       }
 
+    /* security sanity checks
+    if ref: is being used, we can never be sure, but we can take reasonable
+    steps to filter out the most obvious ones.  */
+
+    if ((!uid_not_set && uid == 0) ||
+        (strcmp(username, "root") == 0) ||
+        (strcmp(username, "toor") == 0) )
+      {
+      printf("\n*** Exim's internal user must not be root.\n\n");
+      return 1;
+      }
+
     /* Output user and group names or uid/gid. When names are set, uid/gid
     are set to zero but will be replaced at runtime. */
 
@@ -472,17 +552,20 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
     continue;
     }
 
-  /* CONFIGURE_OWNER is a special case. We look in the environment for
-  CONFIGURE_OWNER. If the value is not numeric, we look up the user. A lot of
-  this code is similar to that for EXIM_USER, but we aren't interested in a gid
-  here, and it's all optional, so just keep it separate. */
+  /* CONFIGURE_OWNER and CONFIGURE_GROUP are special cases. We look in the
+  environment for first. If the value is not numeric, we look up the user or
+  group. A lot of this code is similar to that for EXIM_USER, but it's easier
+  to keep it separate. */
 
-  if (strcmp(name, "CONFIGURE_OWNER") == 0)
+  if (strcmp(name, "CONFIGURE_OWNER") == 0 ||
+      strcmp(name, "CONFIGURE_GROUP") == 0)
     {
+    int isgroup = name[10] == 'G';
     uid_t uid = 0;
+    gid_t gid = 0;
     char *s;
     char *username = NULL;
-    char *user = getenv("CONFIGURE_OWNER");
+    char *user = getenv(name);
 
     if (user == NULL) user = "";
     while (isspace((unsigned char)(*user))) user++;
@@ -496,9 +579,9 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
       {
       if (iscntrl((unsigned char)(*s)))
         {
-        printf("\n*** CONFIGURE_OWNER contains the control character 0x%02X in "
+        printf("\n*** %s contains the control character 0x%02X in "
           "one of the files\n    in the \"Local\" directory. Please review "
-          "your build-time\n    configuration.\n\n", *s);
+          "your build-time\n    configuration.\n\n", name, *s);
         return 1;
         }
       }
@@ -507,10 +590,13 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
 
     if (user[strspn(user, "0123456789")] == 0)
       {
-      uid = (uid_t)atoi(user);
+      if (isgroup)
+        gid = (gid_t)atoi(user);
+      else
+        uid = (uid_t)atoi(user);
       }
 
-    /* User name given. Normally, we look up the uid right away. However,
+    /* Name given. Normally, we look up the uid or gid right away. However,
     people building binary distributions sometimes want to retain the name till
     runtime. This is supported if the name begins "ref:". */
 
@@ -521,6 +607,19 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
       username = user;
       }
 
+    else if (isgroup)
+      {
+      struct group *gr = getgrnam(user);
+      if (gr == NULL)
+        {
+        printf("\n*** Group \"%s\" (specified in one of the Makefiles) does not "
+          "exist.\n    Please review your build-time configuration.\n\n",
+          user);
+        return 1;
+        }
+      gid = gr->gr_gid;
+      }
+
     else
       {
       struct passwd *pw = getpwnam(user);
@@ -531,7 +630,6 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
           user);
         return 1;
         }
-
       uid = pw->pw_uid;
       }
 
@@ -539,8 +637,17 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
     are set to zero but will be replaced at runtime. */
 
     if (username != NULL)
-      fprintf(new, "#define CONFIGURE_OWNERNAME         \"%s\"\n", username);
-    fprintf(new, "#define CONFIGURE_OWNER              %d\n", (int)uid);
+      {
+      if (isgroup)
+        fprintf(new, "#define CONFIGURE_GROUPNAME         \"%s\"\n", username);
+      else
+        fprintf(new, "#define CONFIGURE_OWNERNAME         \"%s\"\n", username);
+      }
+
+    if (isgroup)
+      fprintf(new, "#define CONFIGURE_GROUP              %d\n", (int)gid);
+    else
+      fprintf(new, "#define CONFIGURE_OWNER              %d\n", (int)uid);
     continue;
     }
 
@@ -557,7 +664,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
     else
       {
       int count = 1;
-      int i;
+      int i, j;
       uid_t *vector;
       char *p = list;
       while (*p != 0) if (*p++ == ':') count++;
@@ -565,17 +672,22 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
       vector = malloc((count+1) * sizeof(uid_t));
       vector[0] = (uid_t)count;
 
-      for (i = 1; i <= count; list++, i++)
+      for (i = 1, j = 0; i <= count; list++, i++)
         {
         char name[64];
+
         p = list;
         while (*list != 0 && *list != ':') list++;
         strncpy(name, p, list-p);
         name[list-p] = 0;
 
-        if (name[strspn(name, "0123456789")] == 0)
+        if (name[0] == 0)
+          {
+          continue;
+          }
+        else if (name[strspn(name, "0123456789")] == 0)
           {
-          vector[i] = (uid_t)atoi(name);
+          vector[j++] = (uid_t)atoi(name);
           }
         else
           {
@@ -587,17 +699,30 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
               name);
             return 1;
             }
-          vector[i] = pw->pw_uid;
+          vector[j++] = pw->pw_uid;
           }
         }
-      fprintf(new, "#define FIXED_NEVER_USERS     %d, ", count);
-      for (i = 1; i <= count - 1; i++)
-        fprintf(new, "%d, ", (unsigned int)vector[i]);
-      fprintf(new, "%d\n", (unsigned int)vector[i]);
+      fprintf(new, "#define FIXED_NEVER_USERS     %d", j);
+      for (i = 0; i < j; i++) fprintf(new, ", %d", (unsigned int)vector[i]);
+      fprintf(new, "\n");
       }
     continue;
     }
 
+  /* WITH_CONTENT_SCAN is another special case: it must be set if either it or
+  WITH_OLD_DEMIME is set. */
+
+  if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
+    {
+    char *wcs = getenv("WITH_CONTENT_SCAN");
+    char *wod = getenv("WITH_OLD_DEMIME");
+    char *dcc = getenv("EXPERIMENTAL_DCC");
+    if (wcs != NULL || wod != NULL || dcc != NULL)
+      fprintf(new, "#define WITH_CONTENT_SCAN     yes\n");
+    else fprintf(new, "/* WITH_CONTENT_SCAN not set */\n");
+    continue;
+    }
+
   /* Otherwise, check whether a value exists in the environment. Remember if
   it is an AUTH setting or SUPPORT_CRYPTEQ. */
 
@@ -633,6 +758,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
     else if (strcmp(name, "RADIUS_LIB_TYPE") == 0)
       {
       if (strcmp(value, "RADIUSCLIENT") == 0 ||
+          strcmp(value, "RADIUSCLIENTNEW") == 0 ||
           strcmp(value, "RADLIB") == 0)
         {
         fprintf(new, "#define RADIUS_LIB_%s\n", value);
@@ -727,7 +853,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
     }
   }
 
-fclose(base);
+(void)fclose(base);
 
 /* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
 defined. */
@@ -741,7 +867,7 @@ if (have_auth)
 /* End off */
 
 fprintf(new, "\n/* End of config.h */\n");
-fclose(new);
+(void)fclose(new);
 return 0;
 }