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