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