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