value return
[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 <sys/time.h>
40 #include <poll.h>
41 #include <pwd.h>
42 #include <grp.h>
43
44 typedef struct {
45 const char *name;
46 int *flag;
47 } have_item;
48
49 typedef struct {
50 const char *name;
51 char *data;
52 } save_item;
53
54 static const char *db_opts[] = { "", "USE_DB", "USE_GDBM", "USE_TDB" };
55
56 static int have_ipv6 = 0;
57 static int have_iconv = 0;
58
59 static char errno_quota[256];
60 static char ostype[256];
61 static char cc[256];
62
63 /* If any entry is an initial substring of another, the longer one must
64 appear first. */
65
66 static have_item have_list[] = {
67 { "HAVE_IPV6", &have_ipv6 },
68 { "HAVE_ICONV", &have_iconv },
69 { NULL, NULL}
70 };
71
72 static 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,
81 bomb out. */
82
83 void
84 check_percent_ess(char *value, char *name)
85 {
86 int OK = 0;
87 char *p = strstr(value, "%s");
88 if (p != NULL) OK = strstr(p+2, "%s") == NULL;
89 if (!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
101 int
102 main(int argc, char **argv)
103 {
104 off_t test_off_t = 0;
105 time_t test_time_t = 0;
106 ino_t test_ino_t;
107 #if ! (__STDC_VERSION__ >= 199901L)
108 size_t test_size_t = 0;
109 ssize_t test_ssize_t = 0;
110 unsigned long test_ulong_t = 0L;
111 unsigned int test_uint_t = 0;
112 #endif
113 long test_long_t = 0;
114 long long test_longlong_t = 0;
115 int test_int_t = 0;
116 FILE *base;
117 FILE *new;
118 int last_initial = 'A';
119 int linecount = 0;
120 int have_auth = 0;
121 int in_local_makefile = 0;
122 int use_which_db = 0;
123 int use_which_db_in_local_makefile = 0;
124 int support_crypteq = 0;
125 char buffer[1024];
126
127 if (argc != 1)
128 {
129 printf("*** Buildconfig: called with incorrect arguments\n");
130 exit(1);
131 }
132
133 new = fopen("config.h", "wb");
134 if (new == NULL)
135 {
136 printf("*** Buildconfig: failed to open config.h for output\n");
137 exit(1);
138 }
139
140 printf("Building configuration file config.h\n");
141
142 fprintf(new, "/*************************************************\n");
143 fprintf(new, "* Configuration header for Exim *\n");
144 fprintf(new, "*************************************************/\n\n");
145
146 fprintf(new, "/* This file was automatically generated from Makefile and "
147 "config.h.defaults,\n");
148 fprintf(new, "using values specified in the configuration file Local/Makefile.\n");
149 fprintf(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
153 the size of off_t is greater than 4, "%lld" will be available as a format for
154 printing long long variables, and there will be support for the long long type.
155 This assumption is known to be OK for the common operating systems. */
156
157 fprintf(new, "#ifndef OFF_T_FMT\n");
158 if (sizeof(test_off_t) > sizeof(test_long_t))
159 fprintf(new, "# define OFF_T_FMT \"%%lld\"\n");
160 else
161 fprintf(new, "# define OFF_T_FMT \"%%ld\"\n");
162 fprintf(new, "#endif\n\n");
163
164 fprintf(new, "#ifndef LONGLONG_T\n");
165 if (sizeof(test_longlong_t) > sizeof(test_long_t))
166 fprintf(new, "# define LONGLONG_T long long int\n");
167 else
168 fprintf(new, "# define LONGLONG_T long int\n");
169 fprintf(new, "#endif\n\n");
170
171 /* Now do the same thing for time_t variables. If the length is greater than
172 4, we want to assume long long support (even if off_t was less than 4). If the
173 length is 4 or less, we can leave LONGLONG_T to whatever was defined above for
174 off_t. */
175
176 fprintf(new, "#ifndef TIME_T_FMT\n");
177 if (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 }
183 else
184 fprintf(new, "# define TIME_T_FMT \"%%ld\"\n");
185 fprintf(new, "#endif\n\n");
186
187 fprintf(new, "#ifndef INO_T_FMT\n");
188 if (sizeof(test_ino_t) > sizeof(test_long_t))
189 fprintf(new, "# define INO_T_FMT \"%%llu\"\n");
190 else
191 fprintf(new, "# define INO_T_FMT \"%%lu\"\n");
192 fprintf(new, "#endif\n\n");
193
194 fprintf(new, "#ifndef PID_T_FMT\n");
195 fprintf(new, "# define PID_T_FMT \"%%lu\"\n");
196 fprintf(new, "#endif\n\n");
197
198 /* And for sizeof() results, size_t, which should with C99 be just %zu, deal
199 with C99 not being ubiquitous yet. Unfortunately. Assume ssize_t is same
200 size as size_t on C99; if someone comes up with a version where it's not, fix
201 it then. */
202
203 #if __STDC_VERSION__ >= 199901L
204 fprintf(new, "#define SIZE_T_FMT \"%%zu\"\n");
205 fprintf(new, "#define SSIZE_T_FMT \"%%zd\"\n");
206 #else
207 if (sizeof(test_size_t) > sizeof (test_ulong_t))
208 fprintf(new, "#define SIZE_T_FMT \"%%llu\"\n");
209 else if (sizeof(test_size_t) > sizeof (test_uint_t))
210 fprintf(new, "#define SIZE_T_FMT \"%%lu\"\n");
211 else
212 fprintf(new, "#define SIZE_T_FMT \"%%u\"\n");
213
214 if (sizeof(test_ssize_t) > sizeof(test_long_t))
215 fprintf(new, "#define SSIZE_T_FMT \"%%lld\"\n");
216 else if (sizeof(test_ssize_t) > sizeof(test_int_t))
217 fprintf(new, "#define SSIZE_T_FMT \"%%ld\"\n");
218 else
219 fprintf(new, "#define SSIZE_T_FMT \"%%d\"\n");
220 #endif
221
222 /* Now search the makefile for certain settings */
223
224 base = fopen("Makefile", "rb");
225 if (base == NULL)
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 {
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 }
642 else 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
955 defined. */
956
957 if (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.
962 Some 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
981 fprintf(new, "\n/* End of config.h */\n");
982 (void)fclose(new);
983 return 0;
984 }
985
986 /* End of buildconfig.c */