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 */