tidying
[exim.git] / src / src / buildconfig.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2018 */
6 /* See the file NOTICE for conditions of use and distribution. */
7
8
9 /*************************************************
10 *       Build configuration header for Exim      *
11 *************************************************/
12
13 /* This auxiliary program builds the file config.h by the following
14 process:
15
16 First, it determines the size of off_t and time_t variables, and generates
17 macro code to define OFF_T_FMT and TIME_T_FMT as suitable formats, if they are
18 not already defined in the system-specific header file.
19
20 Then it reads Makefile, looking for certain OS-specific definitions which it
21 uses to define some specific macros. Finally, it reads the defaults file
22 config.h.defaults.
23
24 The defaults file contains normal C #define statements for various macros; if
25 the name of a macro is found in the environment, the environment value replaces
26 the default. If the default #define does not contain any value, then that macro
27 is not copied to the created file unless there is some value in the
28 environment.
29
30 This program is compiled and run as part of the Make process and is not
31 normally called independently. */
32
33
34 #include <ctype.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #include <poll.h>
41 #include <pwd.h>
42 #include <grp.h>
43
44 typedef struct {
45   const char *name;
46   int *flag;
47 } have_item;
48
49 typedef struct {
50   const char *name;
51   char *data;
52 } save_item;
53
54 static const char *db_opts[] = { "", "USE_DB", "USE_GDBM", "USE_TDB" };
55
56 static int have_ipv6 = 0;
57 static int have_iconv = 0;
58
59 static char errno_quota[256];
60 static char ostype[256];
61 static char cc[256];
62
63 /* If any entry is an initial substring of another, the longer one must
64 appear first. */
65
66 static have_item have_list[] = {
67   { "HAVE_IPV6",      &have_ipv6 },
68   { "HAVE_ICONV",     &have_iconv },
69   { NULL, NULL}
70 };
71
72 static save_item save_list[] = {
73   { "ERRNO_QUOTA",    errno_quota },
74   { "OSTYPE",         ostype },
75   { "CC",             cc },
76   { NULL, NULL}
77 };
78
79
80 /* Subroutine to check a string for precisely one instance of "%s". If not,
81 bomb out. */
82
83 void
84 check_percent_ess(char *value, char *name)
85 {
86 int OK = 0;
87 char *p = strstr(value, "%s");
88 if (p != NULL) OK = strstr(p+2, "%s") == NULL;
89 if (!OK)
90   {
91   printf("\n*** \"%s\" (%s) must contain precisely one occurrence of\n"
92     "*** \"%%s\". Please review your build-time configuration.\n\n/", value,
93     name);
94   exit(1);
95   }
96 }
97
98
99 /* Main program */
100
101 int
102 main(int argc, char **argv)
103 {
104 off_t test_off_t = 0;
105 time_t test_time_t = 0;
106 ino_t test_ino_t;
107 #if ! (__STDC_VERSION__ >= 199901L)
108 size_t test_size_t = 0;
109 ssize_t test_ssize_t = 0;
110 unsigned long test_ulong_t = 0L;
111 unsigned int test_uint_t = 0;
112 #endif
113 long test_long_t = 0;
114 int test_int_t = 0;
115 FILE *base;
116 FILE *new;
117 int last_initial = 'A';
118 int linecount = 0;
119 int have_auth = 0;
120 int in_local_makefile = 0;
121 int use_which_db = 0;
122 int use_which_db_in_local_makefile = 0;
123 int support_crypteq = 0;
124 char buffer[1024];
125
126 if (argc != 1)
127   {
128   printf("*** Buildconfig: called with incorrect arguments\n");
129   exit(1);
130   }
131
132 new = fopen("config.h", "wb");
133 if (new == NULL)
134   {
135   printf("*** Buildconfig: failed to open config.h for output\n");
136   exit(1);
137   }
138
139 printf("Building configuration file config.h\n");
140
141 fprintf(new, "/*************************************************\n");
142 fprintf(new, "*           Configuration header for Exim        *\n");
143 fprintf(new, "*************************************************/\n\n");
144
145 fprintf(new, "/* This file was automatically generated from Makefile and "
146   "config.h.defaults,\n");
147 fprintf(new, "using values specified in the configuration file Local/Makefile.\n");
148 fprintf(new, "Do not edit it. Instead, edit Local/Makefile and "
149   "rerun make. */\n\n");
150
151 /* First, deal with the printing format for off_t variables. We assume that if
152 the size of off_t is greater than 4, "%lld" will be available as a format for
153 printing long long variables, and there will be support for the long long type.
154 This assumption is known to be OK for the common operating systems. */
155
156 fprintf(new, "#ifndef OFF_T_FMT\n");
157 if (sizeof(test_off_t) > sizeof(test_long_t))
158   {
159   fprintf(new, "# define OFF_T_FMT  \"%%lld\"\n");
160   fprintf(new, "# define LONGLONG_T long long int\n");
161   }
162 else
163   {
164   fprintf(new, "# define OFF_T_FMT  \"%%ld\"\n");
165   fprintf(new, "# define LONGLONG_T long int\n");
166   }
167 fprintf(new, "#endif\n\n");
168
169 /* Now do the same thing for time_t variables. If the length is greater than
170 4, we want to assume long long support (even if off_t was less than 4). If the
171 length is 4 or less, we can leave LONGLONG_T to whatever was defined above for
172 off_t. */
173
174 fprintf(new, "#ifndef TIME_T_FMT\n");
175 if (sizeof(test_time_t) > sizeof(test_long_t))
176   {
177   fprintf(new, "# define TIME_T_FMT  \"%%lld\"\n");
178   fprintf(new, "# undef  LONGLONG_T\n");
179   fprintf(new, "# define LONGLONG_T long long int\n");
180   }
181 else
182   fprintf(new, "# define TIME_T_FMT  \"%%ld\"\n");
183 fprintf(new, "#endif\n\n");
184
185 fprintf(new, "#ifndef INO_T_FMT\n");
186 if (sizeof(test_ino_t) > sizeof(test_long_t))
187   fprintf(new, "# define INO_T_FMT  \"%%llu\"\n");
188 else
189   fprintf(new, "# define INO_T_FMT  \"%%lu\"\n");
190 fprintf(new, "#endif\n\n");
191
192 fprintf(new, "#ifndef PID_T_FMT\n");
193 fprintf(new, "# define PID_T_FMT  \"%%lu\"\n");
194 fprintf(new, "#endif\n\n");
195
196 /* And for sizeof() results, size_t, which should with C99 be just %zu, deal
197 with C99 not being ubiquitous yet.  Unfortunately.  Assume ssize_t is same
198 size as size_t on C99; if someone comes up with a version where it's not, fix
199 it then. */
200
201 #if __STDC_VERSION__ >= 199901L
202 fprintf(new, "#define SIZE_T_FMT  \"%%zu\"\n");
203 fprintf(new, "#define SSIZE_T_FMT  \"%%zd\"\n");
204 #else
205 if (sizeof(test_size_t) > sizeof (test_ulong_t))
206   fprintf(new, "#define SIZE_T_FMT  \"%%llu\"\n");
207 else if (sizeof(test_size_t) > sizeof (test_uint_t))
208   fprintf(new, "#define SIZE_T_FMT  \"%%lu\"\n");
209 else
210   fprintf(new, "#define SIZE_T_FMT  \"%%u\"\n");
211
212 if (sizeof(test_ssize_t) > sizeof(test_long_t))
213   fprintf(new, "#define SSIZE_T_FMT  \"%%lld\"\n");
214 else if (sizeof(test_ssize_t) > sizeof(test_int_t))
215   fprintf(new, "#define SSIZE_T_FMT  \"%%ld\"\n");
216 else
217   fprintf(new, "#define SSIZE_T_FMT  \"%%d\"\n");
218 #endif
219
220 /* Now search the makefile for certain settings */
221
222 base = fopen("Makefile", "rb");
223 if (base == NULL)
224   {
225   printf("*** Buildconfig: failed to open Makefile\n");
226   (void)fclose(new);
227   exit(1);
228   }
229
230 errno_quota[0] = 0;    /* no over-riding value set */
231 ostype[0] = 0;         /* just in case */
232 cc[0] = 0;
233
234 while (fgets(buffer, sizeof(buffer), base) != NULL)
235   {
236   int i;
237   have_item *h;
238   save_item *s;
239   char *p = buffer + (int)strlen(buffer);
240   linecount++;
241   while (p > buffer && isspace((unsigned char)p[-1])) p--;
242   *p = 0;
243   p = buffer;
244   while (isspace((unsigned char)*p)) p++;
245
246   /* Notice when we hit the user's makefile */
247
248   if (strcmp(p, "# From Local/Makefile") == 0)
249     {
250     in_local_makefile = 1;
251     continue;
252     }
253
254   /* Remember the last DB option setting. If we hit two in the user's
255   Makefile, complain. */
256
257   for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
258     {
259     int len = (int)strlen(db_opts[i]);
260     if (strncmp(p, db_opts[i], len) == 0 && (p[len] == ' ' || p[len] == '='))
261       {
262       if (in_local_makefile)
263         {
264         if (use_which_db_in_local_makefile)
265           {
266           printf("*** Only one of USE_DB, USE_GDBM, or USE_TDB should be "
267             "defined in Local/Makefile\n");
268           exit(1);
269           }
270         use_which_db_in_local_makefile = 1;
271         }
272       use_which_db = i;
273       break;
274       }
275     }
276   if (i < sizeof(db_opts)/sizeof(char *)) continue;
277
278   /* Items where we just save a boolean */
279
280   for (h = have_list; h->name != NULL; h++)
281     {
282     int len = (int)strlen(h->name);
283     if (strncmp(p, h->name, len) == 0)
284       {
285       p += len;
286       while (isspace((unsigned char)*p)) p++;
287       if (*p++ != '=')
288         {
289         printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
290         exit(1);
291         }
292       while (isspace((unsigned char)*p)) p++;
293       if (strcmp(p, "YES") == 0 || strcmp(p, "yes") == 0) *(h->flag) = 1;
294         else *(h->flag) = 0;   /* Must reset in case multiple instances */
295       break;
296       }
297     }
298
299   if (h->name != NULL) continue;
300
301   /* Items where we save the complete string */
302
303   for (s = save_list; s->name != NULL; s++)
304     {
305     int len = (int)strlen(s->name);
306     if (strncmp(p, s->name, len) == 0)
307       {
308       p += len;
309       while (isspace((unsigned char)*p)) p++;
310       if (*p++ != '=')
311         {
312         printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
313         exit(1);
314         }
315       while (isspace((unsigned char)*p)) p++;
316       strcpy(s->data, p);
317       }
318     }
319   }
320
321 fprintf(new, "#define HAVE_IPV6             %s\n",
322   have_ipv6? "TRUE" : "FALSE");
323
324 fprintf(new, "#define HAVE_ICONV            %s\n",
325   have_iconv? "TRUE" : "FALSE");
326
327 if (errno_quota[0] != 0)
328   fprintf(new, "\n#define ERRNO_QUOTA           %s\n", errno_quota);
329
330 if (strcmp(cc, "gcc") == 0 &&
331     (strstr(ostype, "IRIX") != NULL || strstr(ostype, "AIX") != NULL))
332   {
333   fprintf(new, "\n/* This switch includes the code to fix the inet_ntoa() */");
334   fprintf(new, "\n/* bug when using gcc on an IRIX or AIX system. */");
335   fprintf(new, "\n#define USE_INET_NTOA_FIX");
336   }
337
338 fprintf(new, "\n");
339 (void)fclose(base);
340
341
342 /* Now handle the macros listed in the defaults */
343
344 base = fopen("../src/config.h.defaults", "rb");
345 if (base == NULL)
346   {
347   printf("*** Buildconfig: failed to open ../src/config.h.defaults\n");
348   (void)fclose(new);
349   exit(1);
350   }
351
352 while (fgets(buffer, sizeof(buffer), base) != NULL)
353   {
354   int i;
355   char name[256];
356   char *value;
357   char *p = buffer;
358   char *q = name;
359
360   while (*p == ' ' || *p == '\t') p++;
361
362   if (strncmp(p, "#ifdef ", 7) == 0
363    || strncmp(p, "#ifndef ", 8) == 0
364    || strncmp(p, "#if ", 4) == 0
365    || strncmp(p, "#endif", 6) == 0
366      )
367     {
368     fputs(buffer, new);
369     continue;
370     }
371
372   if (strncmp(p, "#define ", 8) != 0) continue;
373
374   p += 8;
375   while (*p == ' ' || *p == '\t') p++;
376
377   if (*p < last_initial) fprintf(new, "\n");
378   last_initial = *p;
379
380   while (*p && (isalnum((unsigned char)*p) || *p == '_')) *q++ = *p++;
381   *q = 0;
382
383   /* USE_DB, USE_GDBM, and USE_TDB are special cases. We want to have only
384   one of them set. The scan of the Makefile has saved which was the last one
385   encountered. */
386
387   for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
388     {
389     if (strcmp(name, db_opts[i]) == 0)
390       {
391       if (use_which_db == i)
392         fprintf(new, "#define %s %.*syes\n", db_opts[i],
393           21 - (int)strlen(db_opts[i]), "                         ");
394       else
395         fprintf(new, "/* %s not set */\n", name);
396       break;
397       }
398     }
399   if (i < sizeof(db_opts)/sizeof(char *)) continue;
400
401   /* EXIM_USER is a special case. We look in the environment for EXIM_USER or
402   EXIM_UID (the latter for backward compatibility with Exim 3). If the value is
403   not numeric, we look up the user, and default the GID if found. Otherwise,
404   EXIM_GROUP or EXIM_GID must be in the environment. */
405
406   if (strcmp(name, "EXIM_UID") == 0)
407     {
408     uid_t uid = 0;
409     gid_t gid = 0;
410     int gid_set = 0;
411     int uid_not_set = 0;
412     char *username = NULL;
413     char *groupname = NULL;
414     char *s;
415     char *user = getenv("EXIM_USER");
416     char *group = getenv("EXIM_GROUP");
417
418     if (user == NULL) user = getenv("EXIM_UID");
419     if (group == NULL) group = getenv("EXIM_GID");
420
421     if (user == NULL)
422       {
423       printf("\n*** EXIM_USER has not been defined in any of the Makefiles in "
424         "the\n    \"Local\" directory. Please review your build-time "
425         "configuration.\n\n");
426       return 1;
427       }
428
429     while (isspace((unsigned char)(*user))) user++;
430     if (*user == 0)
431       {
432       printf("\n*** EXIM_USER is defined as an empty string in one of the "
433         "files\n    in the \"Local\" directory. Please review your build-time"
434         "\n    configuration.\n\n");
435       return 1;
436       }
437
438     for (s = user; *s != 0; s++)
439       {
440       if (iscntrl((unsigned char)(*s)))
441         {
442         printf("\n*** EXIM_USER contains the control character 0x%02X in one "
443           "of the files\n    in the \"Local\" directory. Please review your "
444           "build-time\n    configuration.\n\n", *s);
445         return 1;
446         }
447       }
448
449     /* Numeric uid given */
450
451     if (user[strspn(user, "0123456789")] == 0)
452       {
453       uid = (uid_t)atoi(user);
454       }
455
456     /* User name given. Normally, we look up the uid right away. However,
457     people building binary distributions sometimes want to retain the name till
458     runtime. This is supported if the name begins "ref:". */
459
460     else if (strncmp(user, "ref:", 4) == 0)
461       {
462       user += 4;
463       while (isspace(*user)) user++;
464       username = user;
465       gid_set = 1;
466       uid_not_set = 1;
467       }
468
469     else
470       {
471       struct passwd *pw = getpwnam(user);
472       if (pw == NULL)
473         {
474         printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
475           "exist.\n    Please review your build-time configuration.\n\n",
476           user);
477         return 1;
478         }
479
480       uid = pw->pw_uid;
481       gid = pw->pw_gid;
482       gid_set = 1;
483       }
484
485     /* Use explicit group if set. */
486
487     if (group != NULL)
488       {
489       while (isspace((unsigned char)(*group))) group++;
490       if (*group == 0)
491         {
492         printf("\n*** EXIM_GROUP is defined as an empty string in one of "
493           "the files in the\n    \"Local\" directory. ");
494         if (gid_set)
495           {
496           printf("If you want the Exim group to be taken from the\n    "
497             "password data for the Exim user, just remove the EXIM_GROUP "
498             "setting.\n    Otherwise, p");
499           }
500         else printf("EXIM_USER is defined numerically, so there is no"
501           "\n    default for EXIM_GROUP and you must set it explicitly.\n    P");
502         printf("lease review your build-time configuration.\n\n");
503         return 1;
504         }
505
506       for (s = group; *s != 0; s++)
507         {
508         if (iscntrl((unsigned char)(*s)))
509           {
510           printf("\n*** EXIM_GROUP contains the control character 0x%02X in one "
511             "of the files\n    in the \"Local\" directory. Please review your "
512             "build-time\n    configuration.\n\n", *s);
513           return 1;
514           }
515         }
516
517       /* Group name given. This may be by reference or to be looked up now,
518       as for user. */
519
520       if (strncmp(group, "ref:", 4) == 0)
521         {
522         group += 4;
523         while (isspace(*group)) group++;
524         groupname = group;
525         }
526
527       else if (username != NULL)
528         {
529         groupname = group;
530         }
531
532       else if (group[strspn(group, "0123456789")] == 0)
533         {
534         gid = (gid_t)atoi(group);
535         }
536
537       else
538         {
539         struct group *gr = getgrnam(group);
540         if (gr == NULL)
541           {
542           printf("\n*** Group \"%s\" (specified in one of the Makefiles) does "
543             "not exist.\n   Please review your build-time configuration.\n\n",
544             group);
545           return 1;
546           }
547         gid = gr->gr_gid;
548         }
549       }
550
551     /* Else trouble unless found in passwd file with user */
552
553     else if (!gid_set)
554       {
555       printf("\n*** No group set for Exim. Please review your build-time "
556         "configuration.\n\n");
557       return 1;
558       }
559
560     /* security sanity checks
561     if ref: is being used, we can never be sure, but we can take reasonable
562     steps to filter out the most obvious ones.  */
563
564     if ((!uid_not_set && uid == 0) ||
565         ((username != NULL) && (
566           (strcmp(username, "root") == 0) ||
567           (strcmp(username, "toor") == 0) )))
568       {
569       printf("\n*** Exim's internal user must not be root.\n\n");
570       return 1;
571       }
572
573     /* Output user and group names or uid/gid. When names are set, uid/gid
574     are set to zero but will be replaced at runtime. */
575
576     if (username != NULL)
577       fprintf(new, "#define EXIM_USERNAME         \"%s\"\n", username);
578     if (groupname != NULL)
579       fprintf(new, "#define EXIM_GROUPNAME        \"%s\"\n", groupname);
580
581     fprintf(new, "#define EXIM_UID              %d\n", (int)uid);
582     fprintf(new, "#define EXIM_GID              %d\n", (int)gid);
583     continue;
584     }
585
586   /* CONFIGURE_OWNER and CONFIGURE_GROUP are special cases. We look in the
587   environment for first. If the value is not numeric, we look up the user or
588   group. A lot of this code is similar to that for EXIM_USER, but it's easier
589   to keep it separate. */
590
591   if (strcmp(name, "CONFIGURE_OWNER") == 0 ||
592       strcmp(name, "CONFIGURE_GROUP") == 0)
593     {
594     int isgroup = name[10] == 'G';
595     uid_t uid = 0;
596     gid_t gid = 0;
597     const char *s;
598     const char *username = NULL;
599     const char *user = getenv(name);
600
601     if (user == NULL) user = "";
602     while (isspace((unsigned char)(*user))) user++;
603     if (*user == 0)
604       {
605       fprintf(new, "/* %s not set */\n", name);
606       continue;
607       }
608
609     for (s = user; *s != 0; s++)
610       {
611       if (iscntrl((unsigned char)(*s)))
612         {
613         printf("\n*** %s contains the control character 0x%02X in "
614           "one of the files\n    in the \"Local\" directory. Please review "
615           "your build-time\n    configuration.\n\n", name, *s);
616         return 1;
617         }
618       }
619
620     /* Numeric uid given */
621
622     if (user[strspn(user, "0123456789")] == 0)
623       {
624       if (isgroup)
625         gid = (gid_t)atoi(user);
626       else
627         uid = (uid_t)atoi(user);
628       }
629
630     /* Name given. Normally, we look up the uid or gid right away. However,
631     people building binary distributions sometimes want to retain the name till
632     runtime. This is supported if the name begins "ref:". */
633
634     else if (strncmp(user, "ref:", 4) == 0)
635       {
636       user += 4;
637       while (isspace(*user)) user++;
638       username = user;
639       }
640 else if (isgroup)
641       {
642       struct group *gr = getgrnam(user);
643       if (gr == NULL)
644         {
645         printf("\n*** Group \"%s\" (specified in one of the Makefiles) does not "
646           "exist.\n    Please review your build-time configuration.\n\n",
647           user);
648         return 1;
649         }
650       gid = gr->gr_gid;
651       }
652
653     else
654       {
655       struct passwd *pw = getpwnam(user);
656       if (pw == NULL)
657         {
658         printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
659           "exist.\n    Please review your build-time configuration.\n\n",
660           user);
661         return 1;
662         }
663       uid = pw->pw_uid;
664       }
665
666     /* Output user and group names or uid/gid. When names are set, uid/gid
667     are set to zero but will be replaced at runtime. */
668
669     if (username != NULL)
670       {
671       if (isgroup)
672         fprintf(new, "#define CONFIGURE_GROUPNAME         \"%s\"\n", username);
673       else
674         fprintf(new, "#define CONFIGURE_OWNERNAME         \"%s\"\n", username);
675       }
676
677     if (isgroup)
678       fprintf(new, "#define CONFIGURE_GROUP              %d\n", (int)gid);
679     else
680       fprintf(new, "#define CONFIGURE_OWNER              %d\n", (int)uid);
681     continue;
682     }
683
684   /* FIXED_NEVER_USERS is another special case. Look up the uid values and
685   create suitable initialization data for a vector. */
686
687   if (strcmp(name, "FIXED_NEVER_USERS") == 0)
688     {
689     char *list = getenv("FIXED_NEVER_USERS");
690     if (list == NULL)
691       {
692       fprintf(new, "#define FIXED_NEVER_USERS     0\n");
693       }
694     else
695       {
696       int count = 1;
697       int i, j;
698       uid_t *vector;
699       char *p = list;
700       while (*p != 0) if (*p++ == ':') count++;
701
702       vector = malloc((count+1) * sizeof(uid_t));
703       vector[0] = (uid_t)count;
704
705       for (i = 1, j = 0; i <= count; list++, i++)
706         {
707         char name[64];
708
709         p = list;
710         while (*list != 0 && *list != ':') list++;
711         strncpy(name, p, list-p);
712         name[list-p] = 0;
713
714         if (name[0] == 0)
715           {
716           continue;
717           }
718         else if (name[strspn(name, "0123456789")] == 0)
719           {
720           vector[j++] = (uid_t)atoi(name);
721           }
722         else
723           {
724           struct passwd *pw = getpwnam(name);
725           if (pw == NULL)
726             {
727             printf("\n*** User \"%s\" (specified for FIXED_NEVER_USERS in one of the Makefiles) does not "
728               "exist.\n    Please review your build-time configuration.\n\n",
729               name);
730             return 1;
731             }
732           vector[j++] = pw->pw_uid;
733           }
734         }
735       fprintf(new, "#define FIXED_NEVER_USERS     %d", j);
736       for (i = 0; i < j; i++) fprintf(new, ", %d", (unsigned int)vector[i]);
737       fprintf(new, "\n");
738       free(vector);
739       }
740     continue;
741     }
742
743   /* WITH_CONTENT_SCAN is another special case: it must be set if it or
744   EXPERIMENTAL_DCC is set. */
745
746   if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
747     {
748     char *wcs = getenv("WITH_CONTENT_SCAN");
749     char *dcc = getenv("EXPERIMENTAL_DCC");
750     fprintf(new, wcs || dcc
751       ? "#define WITH_CONTENT_SCAN     yes\n"
752       : "/* WITH_CONTENT_SCAN not set */\n");
753     continue;
754     }
755
756   /* DISABLE_DKIM is special; must be forced if no SUPPORT_TLS */
757   if (strcmp(name, "DISABLE_DKIM") == 0)
758     {
759     char *d_dkim = getenv("DISABLE_DKIM");
760     char *tls = getenv("SUPPORT_TLS");
761
762     if (d_dkim)
763       fprintf(new, "#define DISABLE_DKIM          yes\n");
764     else if (!tls)
765       fprintf(new, "#define DISABLE_DKIM          yes /* forced by lack of TLS */\n");
766     else
767       fprintf(new, "/* DISABLE_DKIM not set */\n");
768     continue;
769     }
770
771   /* Otherwise, check whether a value exists in the environment. Remember if
772   it is an AUTH setting or SUPPORT_CRYPTEQ. */
773
774   if ((value = getenv(name)) != NULL)
775     {
776     int len;
777     len = 21 - (int)strlen(name);
778
779     if (strncmp(name, "AUTH_", 5) == 0) have_auth = 1;
780     if (strncmp(name, "SUPPORT_CRYPTEQ", 15) == 0) support_crypteq = 1;
781
782     /* The text value of LDAP_LIB_TYPE refers to a macro that gets set. */
783
784     if (strcmp(name, "LDAP_LIB_TYPE") == 0)
785       {
786       if (strcmp(value, "NETSCAPE") == 0 ||
787           strcmp(value, "UMICHIGAN") == 0 ||
788           strcmp(value, "OPENLDAP1") == 0 ||
789           strcmp(value, "OPENLDAP2") == 0 ||
790           strcmp(value, "SOLARIS") == 0 ||
791           strcmp(value, "SOLARIS7") == 0)              /* Compatibility */
792         {
793         fprintf(new, "#define LDAP_LIB_%s\n", value);
794         }
795       else
796         {
797         printf("\n*** LDAP_LIB_TYPE=%s is not a recognized LDAP library type."
798           "\n*** Please review your build-time configuration.\n\n", value);
799         return 1;
800         }
801       }
802
803     else if (strcmp(name, "RADIUS_LIB_TYPE") == 0)
804       {
805       if (strcmp(value, "RADIUSCLIENT") == 0 ||
806           strcmp(value, "RADIUSCLIENTNEW") == 0 ||
807           strcmp(value, "RADLIB") == 0)
808         {
809         fprintf(new, "#define RADIUS_LIB_%s\n", value);
810         }
811       else
812         {
813         printf("\n*** RADIUS_LIB_TYPE=%s is not a recognized RADIUS library type."
814           "\n*** Please review your build-time configuration.\n\n", value);
815         return 1;
816         }
817       }
818
819     /* Other macros get set to the environment value. */
820
821     else
822       {
823       fprintf(new, "#define %s ", name);
824       while(len-- > 0) fputc(' ', new);
825
826       /* LOG_FILE_PATH is now messy because it can be a path containing %s or
827       it can be "syslog" or ":syslog" or "syslog:path" or even "path:syslog". */
828
829       if (strcmp(name, "LOG_FILE_PATH") == 0)
830         {
831         char *ss = value;
832         for(;;)
833           {
834           char *pp;
835           char *sss = strchr(ss, ':');
836           if (sss != NULL)
837             {
838             strncpy(buffer, ss, sss-ss);
839             buffer[sss-ss] = 0;  /* For empty case */
840             }
841           else
842             {
843             strncpy(buffer, ss, sizeof(buffer));
844             buffer[sizeof(buffer)-1] = 0;
845             }
846           pp = buffer + (int)strlen(buffer);
847           while (pp > buffer && isspace((unsigned char)pp[-1])) pp--;
848           *pp = 0;
849           if (buffer[0] != 0 && strcmp(buffer, "syslog") != 0)
850             check_percent_ess(buffer, name);
851           if (sss == NULL) break;
852           ss = sss + 1;
853           while (isspace((unsigned char)*ss)) ss++;
854           }
855         fprintf(new, "\"%s\"\n", value);
856         }
857
858       /* Timezone values HEADERS_CHARSET, TCP_WRAPPERS_DAEMON_NAME and
859       WHITELIST_D_MACROS get quoted */
860
861       else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
862                strcmp(name, "TCP_WRAPPERS_DAEMON_NAME") == 0||
863                strcmp(name, "HEADERS_CHARSET") == 0||
864                strcmp(name, "WHITELIST_D_MACROS") == 0)
865         fprintf(new, "\"%s\"\n", value);
866
867       /* GnuTLS constants; first is for debugging, others are tuning */
868
869       /* less than 0 is not-active; 0-9 are normal, API suggests higher
870       taken without problems */
871       else if (strcmp(name, "EXIM_GNUTLS_LIBRARY_LOG_LEVEL") == 0)
872         {
873         long nv;
874         char *end;
875         nv = strtol(value, &end, 10);
876         if (end != value && *end == '\0' && nv >= -1 && nv <= 100)
877           {
878           fprintf(new, "%s\n", value);
879           }
880         else
881           {
882           printf("Value of %s should be -1..9\n", name);
883           return 1;
884           }
885         }
886
887       /* how many bits Exim, as a client, demands must be in D-H */
888       /* 1024 is a historical figure; some sites actually use lower, so we
889       permit the value to be lowered "dangerously" low, but not "insanely"
890       low.  Though actually, 1024 is becoming "dangerous". */
891       else if ((strcmp(name, "EXIM_CLIENT_DH_MIN_MIN_BITS") == 0) ||
892                (strcmp(name, "EXIM_CLIENT_DH_DEFAULT_MIN_BITS") == 0) ||
893                (strcmp(name, "EXIM_SERVER_DH_BITS_PRE2_12") == 0))
894         {
895         long nv;
896         char *end;
897         nv = strtol(value, &end, 10);
898         if (end != value && *end == '\0' && nv >= 512 && nv < 500000)
899           {
900           fprintf(new, "%s\n", value);
901           }
902         else
903           {
904           printf("Unreasonable value (%s) of \"%s\".\n", value, name);
905           return 1;
906           }
907         }
908
909       /* For others, quote any paths and don't quote anything else */
910
911       else
912         {
913         if (value[0] == '/') fprintf(new, "\"%s\"\n", value);
914           else fprintf(new, "%s\n", value);
915         }
916       }
917     }
918
919   /* Value not defined in the environment; use the default */
920
921   else
922     {
923     char *t = p;
924     while (*p == ' ' || *p == '\t') p++;
925     if (*p != '\n') fputs(buffer, new); else
926       {
927       *t = 0;
928       if (strcmp(name, "BIN_DIRECTORY")   == 0 ||
929           strcmp(name, "CONFIGURE_FILE")  == 0)
930         {
931         printf("\n*** %s has not been defined in any of the Makefiles in the\n"
932           "    \"Local\" directory. "
933           "Please review your build-time configuration.\n\n", name);
934         return 1;
935         }
936
937       if (strcmp(name, "TIMEZONE_DEFAULT") == 0)
938         {
939         char *tz = getenv("TZ");
940         fprintf(new, "#define TIMEZONE_DEFAULT      ");
941         if (tz == NULL) fprintf(new, "NULL\n"); else
942           fprintf(new, "\"%s\"\n", tz);
943         }
944
945       else fprintf(new, "/* %s not set */\n", name);
946       }
947     }
948   }
949
950 (void)fclose(base);
951
952 /* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
953 defined. */
954
955 if (have_auth)
956   if (!support_crypteq) fprintf(new, "/* Force SUPPORT_CRYPTEQ for AUTH */\n"
957     "#define SUPPORT_CRYPTEQ\n");
958
959 /* Check poll() for timer functionality.
960 Some OS' have released with it broken. */
961
962   {
963   struct timeval before, after;
964   size_t us;
965
966   gettimeofday(&before, NULL);
967   (void) poll(NULL, 0, 500);
968   gettimeofday(&after, NULL);
969
970   us = (after.tv_sec - before.tv_sec) * 1000000 +
971     (after.tv_usec - before.tv_usec);
972
973   if (us < 400000)
974     fprintf(new, "#define NO_POLL_H\n");
975   }
976
977 /* End off */
978
979 fprintf(new, "\n/* End of config.h */\n");
980 (void)fclose(new);
981 return 0;
982 }
983
984 /* End of buildconfig.c */