EXPERIMENTAL_DCC: make build without WITH_CONTENT_SCAN fail
[exim.git] / src / src / buildconfig.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2022 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8
9
10 /*************************************************
11 *       Build configuration header for Exim      *
12 *************************************************/
13
14 /* This auxiliary program builds the file config.h by the following
15 process:
16
17 First, it determines the size of off_t and time_t variables, and generates
18 macro code to define OFF_T_FMT and TIME_T_FMT as suitable formats, if they are
19 not already defined in the system-specific header file.
20
21 Then it reads Makefile, looking for certain OS-specific definitions which it
22 uses to define some specific macros. Finally, it reads the defaults file
23 config.h.defaults.
24
25 The defaults file contains normal C #define statements for various macros; if
26 the name of a macro is found in the environment, the environment value replaces
27 the default. If the default #define does not contain any value, then that macro
28 is not copied to the created file unless there is some value in the
29 environment.
30
31 This program is compiled and run as part of the Make process and is not
32 normally called independently. */
33
34
35 #include <ctype.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/time.h>
41 #include <poll.h>
42 #include <pwd.h>
43 #include <grp.h>
44
45 typedef struct {
46   const char *name;
47   int *flag;
48 } have_item;
49
50 typedef struct {
51   const char *name;
52   char *data;
53 } save_item;
54
55 static const char *db_opts[] = { "", "USE_DB", "USE_GDBM", "USE_TDB", "USE_NDBM" };
56
57 static int have_ipv6 = 0;
58 static int have_iconv = 0;
59
60 static char errno_quota[256];
61 static char ostype[256];
62 static char cc[256];
63
64 /* If any entry is an initial substring of another, the longer one must
65 appear first. */
66
67 static have_item have_list[] = {
68   { "HAVE_IPV6",      &have_ipv6 },
69   { "HAVE_ICONV",     &have_iconv },
70   { NULL, NULL}
71 };
72
73 static save_item save_list[] = {
74   { "ERRNO_QUOTA",    errno_quota },
75   { "OSTYPE",         ostype },
76   { "CC",             cc },
77   { NULL, NULL}
78 };
79
80
81 /* Subroutine to check a string for precisely one instance of "%s". If not,
82 bomb out. */
83
84 void
85 check_percent_ess(char *value, char *name)
86 {
87 int OK = 0;
88 char *p = strstr(value, "%s");
89 if (p != NULL) OK = strstr(p+2, "%s") == NULL;
90 if (!OK)
91   {
92   printf("\n*** \"%s\" (%s) must contain precisely one occurrence of\n"
93     "*** \"%%s\". Please review your build-time configuration.\n\n/", value,
94     name);
95   exit(1);
96   }
97 }
98
99
100 /* Main program */
101
102 int
103 main(int argc, char **argv)
104 {
105 off_t test_off_t = 0;
106 time_t test_time_t = 0;
107 ino_t test_ino_t;
108 #if ! (__STDC_VERSION__ >= 199901L)
109 size_t test_size_t = 0;
110 ssize_t test_ssize_t = 0;
111 unsigned long test_ulong_t = 0L;
112 unsigned int test_uint_t = 0;
113 #endif
114 long test_long_t = 0;
115 long long test_longlong_t = 0;
116 int test_int_t = 0;
117 FILE *base;
118 FILE *new;
119 int last_initial = 'A';
120 int linecount = 0;
121 int have_auth = 0;
122 int in_local_makefile = 0;
123 int use_which_db = 0;
124 int use_which_db_in_local_makefile = 0;
125 int support_crypteq = 0;
126 char buffer[1024];
127
128 if (argc != 1)
129   {
130   printf("*** Buildconfig: called with incorrect arguments\n");
131   exit(1);
132   }
133
134 new = fopen("config.h", "wb");
135 if (new == NULL)
136   {
137   printf("*** Buildconfig: failed to open config.h for output\n");
138   exit(1);
139   }
140
141 printf("Building configuration file config.h\n");
142
143 fprintf(new, "/*************************************************\n");
144 fprintf(new, "*           Configuration header for Exim        *\n");
145 fprintf(new, "*************************************************/\n\n");
146
147 fprintf(new, "/* This file was automatically generated from Makefile and "
148   "config.h.defaults,\n");
149 fprintf(new, "using values specified in the configuration file Local/Makefile.\n");
150 fprintf(new, "Do not edit it. Instead, edit Local/Makefile and "
151   "rerun make. */\n\n");
152
153 /* First, deal with the printing format for off_t variables. We assume that if
154 the size of off_t is greater than 4, "%lld" will be available as a format for
155 printing long long variables, and there will be support for the long long type.
156 This assumption is known to be OK for the common operating systems. */
157
158 fprintf(new, "#ifndef OFF_T_FMT\n");
159 if (sizeof(test_off_t) > sizeof(test_long_t))
160   fprintf(new, "# define OFF_T_FMT  \"%%lld\"\n");
161 else
162   fprintf(new, "# define OFF_T_FMT  \"%%ld\"\n");
163 fprintf(new, "#endif\n\n");
164
165 fprintf(new, "#ifndef LONGLONG_T\n");
166 if (sizeof(test_longlong_t) > sizeof(test_long_t))
167   fprintf(new, "# define LONGLONG_T long long int\n");
168 else
169   fprintf(new, "# define LONGLONG_T long int\n");
170 fprintf(new, "#endif\n\n");
171
172 /* Now do the same thing for time_t variables. If the length is greater than
173 4, we want to assume long long support (even if off_t was less than 4). If the
174 length is 4 or less, we can leave LONGLONG_T to whatever was defined above for
175 off_t. */
176
177 fprintf(new, "#ifndef TIME_T_FMT\n");
178 if (sizeof(test_time_t) > sizeof(test_long_t))
179   {
180   fprintf(new, "# define TIME_T_FMT  \"%%lld\"\n");
181   fprintf(new, "# undef  LONGLONG_T\n");
182   fprintf(new, "# define LONGLONG_T long long int\n");
183   }
184 else
185   fprintf(new, "# define TIME_T_FMT  \"%%ld\"\n");
186 fprintf(new, "#endif\n\n");
187
188 fprintf(new, "#ifndef INO_T_FMT\n");
189 if (sizeof(test_ino_t) > sizeof(test_long_t))
190   fprintf(new, "# define INO_T_FMT  \"%%llu\"\n");
191 else
192   fprintf(new, "# define INO_T_FMT  \"%%lu\"\n");
193 fprintf(new, "#endif\n\n");
194
195 fprintf(new, "#ifndef PID_T_FMT\n");
196 fprintf(new, "# define PID_T_FMT  \"%%lu\"\n");
197 fprintf(new, "#endif\n\n");
198
199 /* And for sizeof() results, size_t, which should with C99 be just %zu, deal
200 with C99 not being ubiquitous yet.  Unfortunately.  Assume ssize_t is same
201 size as size_t on C99; if someone comes up with a version where it's not, fix
202 it then. */
203
204 #if __STDC_VERSION__ >= 199901L
205 fprintf(new, "#define SIZE_T_FMT  \"%%zu\"\n");
206 fprintf(new, "#define SSIZE_T_FMT  \"%%zd\"\n");
207 #else
208 if (sizeof(test_size_t) > sizeof (test_ulong_t))
209   fprintf(new, "#define SIZE_T_FMT  \"%%llu\"\n");
210 else if (sizeof(test_size_t) > sizeof (test_uint_t))
211   fprintf(new, "#define SIZE_T_FMT  \"%%lu\"\n");
212 else
213   fprintf(new, "#define SIZE_T_FMT  \"%%u\"\n");
214
215 if (sizeof(test_ssize_t) > sizeof(test_long_t))
216   fprintf(new, "#define SSIZE_T_FMT  \"%%lld\"\n");
217 else if (sizeof(test_ssize_t) > sizeof(test_int_t))
218   fprintf(new, "#define SSIZE_T_FMT  \"%%ld\"\n");
219 else
220   fprintf(new, "#define SSIZE_T_FMT  \"%%d\"\n");
221 #endif
222
223 /* Now search the makefile for certain settings */
224
225 if (!(base = fopen("Makefile", "rb")))
226   {
227   printf("*** Buildconfig: failed to open Makefile\n");
228   (void)fclose(new);
229   exit(1);
230   }
231
232 errno_quota[0] = 0;    /* no over-riding value set */
233 ostype[0] = 0;         /* just in case */
234 cc[0] = 0;
235
236 while (fgets(buffer, sizeof(buffer), base) != NULL)
237   {
238   int i;
239   have_item *h;
240   save_item *s;
241   char *p = buffer + (int)strlen(buffer);
242   linecount++;
243   while (p > buffer && isspace((unsigned char)p[-1])) p--;
244   *p = 0;
245   p = buffer;
246   while (isspace((unsigned char)*p)) p++;
247
248   /* Notice when we hit the user's makefile */
249
250   if (strcmp(p, "# From Local/Makefile") == 0)
251     {
252     in_local_makefile = 1;
253     continue;
254     }
255
256   /* Remember the last DB option setting. If we hit two in the user's
257   Makefile, complain. */
258
259   for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
260     {
261     int len = (int)strlen(db_opts[i]);
262     if (strncmp(p, db_opts[i], len) == 0 && (p[len] == ' ' || p[len] == '='))
263       {
264       if (in_local_makefile)
265         {
266         if (use_which_db_in_local_makefile)
267           {
268           printf("*** Only one of USE_DB, USE_GDBM, or USE_TDB should be "
269             "defined in Local/Makefile\n");
270           exit(1);
271           }
272         use_which_db_in_local_makefile = 1;
273         }
274       use_which_db = i;
275       break;
276       }
277     }
278   if (i < sizeof(db_opts)/sizeof(char *)) continue;
279
280   /* Items where we just save a boolean */
281
282   for (h = have_list; h->name != NULL; h++)
283     {
284     int len = (int)strlen(h->name);
285     if (strncmp(p, h->name, len) == 0)
286       {
287       p += len;
288       while (isspace((unsigned char)*p)) p++;
289       if (*p++ != '=')
290         {
291         printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
292         exit(1);
293         }
294       while (isspace((unsigned char)*p)) p++;
295       if (strcmp(p, "YES") == 0 || strcmp(p, "yes") == 0) *(h->flag) = 1;
296         else *(h->flag) = 0;   /* Must reset in case multiple instances */
297       break;
298       }
299     }
300
301   if (h->name != NULL) continue;
302
303   /* Items where we save the complete string */
304
305   for (s = save_list; s->name != NULL; s++)
306     {
307     int len = (int)strlen(s->name);
308     if (strncmp(p, s->name, len) == 0)
309       {
310       p += len;
311       while (isspace((unsigned char)*p)) p++;
312       if (*p++ != '=')
313         {
314         printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
315         exit(1);
316         }
317       while (isspace((unsigned char)*p)) p++;
318       strcpy(s->data, p);
319       }
320     }
321   }
322
323 fprintf(new, "#define HAVE_IPV6             %s\n",
324   have_ipv6? "TRUE" : "FALSE");
325
326 fprintf(new, "#define HAVE_ICONV            %s\n",
327   have_iconv? "TRUE" : "FALSE");
328
329 if (errno_quota[0] != 0)
330   fprintf(new, "\n#define ERRNO_QUOTA           %s\n", errno_quota);
331
332 if (strcmp(cc, "gcc") == 0 &&
333     (strstr(ostype, "IRIX") != NULL || strstr(ostype, "AIX") != NULL))
334   {
335   fprintf(new, "\n/* This switch includes the code to fix the inet_ntoa() */");
336   fprintf(new, "\n/* bug when using gcc on an IRIX or AIX system. */");
337   fprintf(new, "\n#define USE_INET_NTOA_FIX");
338   }
339
340 fprintf(new, "\n");
341 (void)fclose(base);
342
343
344 /* Now handle the macros listed in the defaults */
345
346 base = fopen("../src/config.h.defaults", "rb");
347 if (base == NULL)
348   {
349   printf("*** Buildconfig: failed to open ../src/config.h.defaults\n");
350   (void)fclose(new);
351   exit(1);
352   }
353
354 while (fgets(buffer, sizeof(buffer), base) != NULL)
355   {
356   int i;
357   char name[256];
358   char *value;
359   char *p = buffer;
360   char *q = name;
361
362   while (*p == ' ' || *p == '\t') p++;
363
364   if (strncmp(p, "#ifdef ", 7) == 0
365    || strncmp(p, "#ifndef ", 8) == 0
366    || strncmp(p, "#if ", 4) == 0
367    || strncmp(p, "#endif", 6) == 0
368      )
369     {
370     fputs(buffer, new);
371     continue;
372     }
373
374   if (strncmp(p, "#define ", 8) != 0) continue;
375
376   p += 8;
377   while (*p == ' ' || *p == '\t') p++;
378
379   if (*p < last_initial) fprintf(new, "\n");
380   last_initial = *p;
381
382   while (*p && (isalnum((unsigned char)*p) || *p == '_')) *q++ = *p++;
383   *q = 0;
384
385   /* USE_DB, USE_GDBM, and USE_TDB are special cases. We want to have only
386   one of them set. The scan of the Makefile has saved which was the last one
387   encountered. */
388
389   for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
390     if (strcmp(name, db_opts[i]) == 0)
391       {
392       if (use_which_db == i)
393         fprintf(new, "#define %s %.*syes\n", db_opts[i],
394           21 - (int)strlen(db_opts[i]), "                         ");
395       else
396         fprintf(new, "/* %s not set */\n", name);
397       break;
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   /* DISABLE_DKIM is special; must be forced if DISABLE_TLS */
744   if (strcmp(name, "DISABLE_DKIM") == 0)
745     {
746     char *d_dkim = getenv("DISABLE_DKIM");
747     char *notls = getenv("DISABLE_TLS");
748
749     if (d_dkim)
750       fprintf(new, "#define DISABLE_DKIM          yes\n");
751     else if (notls)
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
829             {
830             strncpy(buffer, ss, sizeof(buffer));
831             buffer[sizeof(buffer)-1] = 0;
832             }
833           pp = buffer + (int)strlen(buffer);
834           while (pp > buffer && isspace((unsigned char)pp[-1])) pp--;
835           *pp = 0;
836           if (buffer[0] != 0 && strcmp(buffer, "syslog") != 0)
837             check_percent_ess(buffer, name);
838           if (sss == NULL) break;
839           ss = sss + 1;
840           while (isspace((unsigned char)*ss)) ss++;
841           }
842         fprintf(new, "\"%s\"\n", value);
843         }
844
845       /* Timezone values HEADERS_CHARSET, TCP_WRAPPERS_DAEMON_NAME and
846       WHITELIST_D_MACROS get quoted */
847
848       else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
849                strcmp(name, "TCP_WRAPPERS_DAEMON_NAME") == 0||
850                strcmp(name, "HEADERS_CHARSET") == 0||
851                strcmp(name, "WHITELIST_D_MACROS") == 0)
852         fprintf(new, "\"%s\"\n", value);
853
854       /* GnuTLS constants; first is for debugging, others are tuning */
855
856       /* less than 0 is not-active; 0-9 are normal, API suggests higher
857       taken without problems */
858       else if (strcmp(name, "EXIM_GNUTLS_LIBRARY_LOG_LEVEL") == 0)
859         {
860         long nv;
861         char *end;
862         nv = strtol(value, &end, 10);
863         if (end != value && *end == '\0' && nv >= -1 && nv <= 100)
864           {
865           fprintf(new, "%s\n", value);
866           }
867         else
868           {
869           printf("Value of %s should be -1..9\n", name);
870           return 1;
871           }
872         }
873
874       /* how many bits Exim, as a client, demands must be in D-H */
875       /* 1024 is a historical figure; some sites actually use lower, so we
876       permit the value to be lowered "dangerously" low, but not "insanely"
877       low.  Though actually, 1024 is becoming "dangerous". */
878       else if ((strcmp(name, "EXIM_CLIENT_DH_MIN_MIN_BITS") == 0) ||
879                (strcmp(name, "EXIM_CLIENT_DH_DEFAULT_MIN_BITS") == 0) ||
880                (strcmp(name, "EXIM_SERVER_DH_BITS_PRE2_12") == 0))
881         {
882         long nv;
883         char *end;
884         nv = strtol(value, &end, 10);
885         if (end != value && *end == '\0' && nv >= 512 && nv < 500000)
886           {
887           fprintf(new, "%s\n", value);
888           }
889         else
890           {
891           printf("Unreasonable value (%s) of \"%s\".\n", value, name);
892           return 1;
893           }
894         }
895
896       /* For others, quote any paths and don't quote anything else */
897
898       else
899         {
900         if (value[0] == '/') fprintf(new, "\"%s\"\n", value);
901           else fprintf(new, "%s\n", value);
902         }
903       }
904     }
905
906   /* Value not defined in the environment; use the default */
907
908   else
909     {
910     char *t = p;
911     while (*p == ' ' || *p == '\t') p++;
912     if (*p != '\n') fputs(buffer, new); else
913       {
914       *t = 0;
915       if (strcmp(name, "BIN_DIRECTORY")   == 0 ||
916           strcmp(name, "CONFIGURE_FILE")  == 0)
917         {
918         printf("\n*** %s has not been defined in any of the Makefiles in the\n"
919           "    \"Local\" directory. "
920           "Please review your build-time configuration.\n\n", name);
921         return 1;
922         }
923
924       if (strcmp(name, "TIMEZONE_DEFAULT") == 0)
925         {
926         char *tz = getenv("TZ");
927         fprintf(new, "#define TIMEZONE_DEFAULT      ");
928         if (tz == NULL) fprintf(new, "NULL\n"); else
929           fprintf(new, "\"%s\"\n", tz);
930         }
931
932       else fprintf(new, "/* %s not set */\n", name);
933       }
934     }
935   }
936
937 (void)fclose(base);
938
939 /* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
940 defined. */
941
942 if (have_auth)
943   if (!support_crypteq) fprintf(new, "/* Force SUPPORT_CRYPTEQ for AUTH */\n"
944     "#define SUPPORT_CRYPTEQ\n");
945
946 /* Check poll() for timer functionality.
947 Some OS' have released with it broken. */
948
949   {
950   struct timeval before, after;
951   size_t us;
952
953   gettimeofday(&before, NULL);
954   (void) poll(NULL, 0, 500);
955   gettimeofday(&after, NULL);
956
957   us = (after.tv_sec - before.tv_sec) * 1000000 +
958     (after.tv_usec - before.tv_usec);
959
960   if (us < 400000)
961     fprintf(new, "#define NO_POLL_H\n");
962   }
963
964 /* End off */
965
966 fprintf(new, "\n/* End of config.h */\n");
967 (void)fclose(new);
968 return 0;
969 }
970
971 /* End of buildconfig.c */