Fix dec64table[] OOB read in b64decode()
[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 }
737 continue;
738 }
739
740 /* WITH_CONTENT_SCAN is another special case: it must be set if it or
741 EXPERIMENTAL_DCC is set. */
742
743 if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
744 {
745 char *wcs = getenv("WITH_CONTENT_SCAN");
746 char *dcc = getenv("EXPERIMENTAL_DCC");
747 fprintf(new, wcs || dcc
748 ? "#define WITH_CONTENT_SCAN yes\n"
749 : "/* WITH_CONTENT_SCAN not set */\n");
750 continue;
751 }
752
753 /* DISABLE_DKIM is special; must be forced if no SUPPORT_TLS */
754 if (strcmp(name, "DISABLE_DKIM") == 0)
755 {
756 char *d_dkim = getenv("DISABLE_DKIM");
757 char *tls = getenv("SUPPORT_TLS");
758
759 if (d_dkim)
760 fprintf(new, "#define DISABLE_DKIM yes\n");
761 else if (!tls)
762 fprintf(new, "#define DISABLE_DKIM yes /* forced by lack of TLS */\n");
763 else
764 fprintf(new, "/* DISABLE_DKIM not set */\n");
765 continue;
766 }
767
768 /* Otherwise, check whether a value exists in the environment. Remember if
769 it is an AUTH setting or SUPPORT_CRYPTEQ. */
770
771 if ((value = getenv(name)) != NULL)
772 {
773 int len;
774 len = 21 - (int)strlen(name);
775
776 if (strncmp(name, "AUTH_", 5) == 0) have_auth = 1;
777 if (strncmp(name, "SUPPORT_CRYPTEQ", 15) == 0) support_crypteq = 1;
778
779 /* The text value of LDAP_LIB_TYPE refers to a macro that gets set. */
780
781 if (strcmp(name, "LDAP_LIB_TYPE") == 0)
782 {
783 if (strcmp(value, "NETSCAPE") == 0 ||
784 strcmp(value, "UMICHIGAN") == 0 ||
785 strcmp(value, "OPENLDAP1") == 0 ||
786 strcmp(value, "OPENLDAP2") == 0 ||
787 strcmp(value, "SOLARIS") == 0 ||
788 strcmp(value, "SOLARIS7") == 0) /* Compatibility */
789 {
790 fprintf(new, "#define LDAP_LIB_%s\n", value);
791 }
792 else
793 {
794 printf("\n*** LDAP_LIB_TYPE=%s is not a recognized LDAP library type."
795 "\n*** Please review your build-time configuration.\n\n", value);
796 return 1;
797 }
798 }
799
800 else if (strcmp(name, "RADIUS_LIB_TYPE") == 0)
801 {
802 if (strcmp(value, "RADIUSCLIENT") == 0 ||
803 strcmp(value, "RADIUSCLIENTNEW") == 0 ||
804 strcmp(value, "RADLIB") == 0)
805 {
806 fprintf(new, "#define RADIUS_LIB_%s\n", value);
807 }
808 else
809 {
810 printf("\n*** RADIUS_LIB_TYPE=%s is not a recognized RADIUS library type."
811 "\n*** Please review your build-time configuration.\n\n", value);
812 return 1;
813 }
814 }
815
816 /* Other macros get set to the environment value. */
817
818 else
819 {
820 fprintf(new, "#define %s ", name);
821 while(len-- > 0) fputc(' ', new);
822
823 /* LOG_FILE_PATH is now messy because it can be a path containing %s or
824 it can be "syslog" or ":syslog" or "syslog:path" or even "path:syslog". */
825
826 if (strcmp(name, "LOG_FILE_PATH") == 0)
827 {
828 char *ss = value;
829 for(;;)
830 {
831 char *pp;
832 char *sss = strchr(ss, ':');
833 if (sss != NULL)
834 {
835 strncpy(buffer, ss, sss-ss);
836 buffer[sss-ss] = 0; /* For empty case */
837 }
838 else
839 {
840 strncpy(buffer, ss, sizeof(buffer));
841 buffer[sizeof(buffer)-1] = 0;
842 }
843 pp = buffer + (int)strlen(buffer);
844 while (pp > buffer && isspace((unsigned char)pp[-1])) pp--;
845 *pp = 0;
846 if (buffer[0] != 0 && strcmp(buffer, "syslog") != 0)
847 check_percent_ess(buffer, name);
848 if (sss == NULL) break;
849 ss = sss + 1;
850 while (isspace((unsigned char)*ss)) ss++;
851 }
852 fprintf(new, "\"%s\"\n", value);
853 }
854
855 /* Timezone values HEADERS_CHARSET, TCP_WRAPPERS_DAEMON_NAME and
856 WHITELIST_D_MACROS get quoted */
857
858 else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
859 strcmp(name, "TCP_WRAPPERS_DAEMON_NAME") == 0||
860 strcmp(name, "HEADERS_CHARSET") == 0||
861 strcmp(name, "WHITELIST_D_MACROS") == 0)
862 fprintf(new, "\"%s\"\n", value);
863
864 /* GnuTLS constants; first is for debugging, others are tuning */
865
866 /* less than 0 is not-active; 0-9 are normal, API suggests higher
867 taken without problems */
868 else if (strcmp(name, "EXIM_GNUTLS_LIBRARY_LOG_LEVEL") == 0)
869 {
870 long nv;
871 char *end;
872 nv = strtol(value, &end, 10);
873 if (end != value && *end == '\0' && nv >= -1 && nv <= 100)
874 {
875 fprintf(new, "%s\n", value);
876 }
877 else
878 {
879 printf("Value of %s should be -1..9\n", name);
880 return 1;
881 }
882 }
883
884 /* how many bits Exim, as a client, demands must be in D-H */
885 /* 1024 is a historical figure; some sites actually use lower, so we
886 permit the value to be lowered "dangerously" low, but not "insanely"
887 low. Though actually, 1024 is becoming "dangerous". */
888 else if ((strcmp(name, "EXIM_CLIENT_DH_MIN_MIN_BITS") == 0) ||
889 (strcmp(name, "EXIM_CLIENT_DH_DEFAULT_MIN_BITS") == 0) ||
890 (strcmp(name, "EXIM_SERVER_DH_BITS_PRE2_12") == 0))
891 {
892 long nv;
893 char *end;
894 nv = strtol(value, &end, 10);
895 if (end != value && *end == '\0' && nv >= 512 && nv < 500000)
896 {
897 fprintf(new, "%s\n", value);
898 }
899 else
900 {
901 printf("Unreasonable value (%s) of \"%s\".\n", value, name);
902 return 1;
903 }
904 }
905
906 /* For others, quote any paths and don't quote anything else */
907
908 else
909 {
910 if (value[0] == '/') fprintf(new, "\"%s\"\n", value);
911 else fprintf(new, "%s\n", value);
912 }
913 }
914 }
915
916 /* Value not defined in the environment; use the default */
917
918 else
919 {
920 char *t = p;
921 while (*p == ' ' || *p == '\t') p++;
922 if (*p != '\n') fputs(buffer, new); else
923 {
924 *t = 0;
925 if (strcmp(name, "BIN_DIRECTORY") == 0 ||
926 strcmp(name, "CONFIGURE_FILE") == 0)
927 {
928 printf("\n*** %s has not been defined in any of the Makefiles in the\n"
929 " \"Local\" directory. "
930 "Please review your build-time configuration.\n\n", name);
931 return 1;
932 }
933
934 if (strcmp(name, "TIMEZONE_DEFAULT") == 0)
935 {
936 char *tz = getenv("TZ");
937 fprintf(new, "#define TIMEZONE_DEFAULT ");
938 if (tz == NULL) fprintf(new, "NULL\n"); else
939 fprintf(new, "\"%s\"\n", tz);
940 }
941
942 else fprintf(new, "/* %s not set */\n", name);
943 }
944 }
945 }
946
947 (void)fclose(base);
948
949 /* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
950 defined. */
951
952 if (have_auth)
953 {
954 if (!support_crypteq) fprintf(new, "/* Force SUPPORT_CRYPTEQ for AUTH */\n"
955 "#define SUPPORT_CRYPTEQ\n");
956 }
957
958 /* End off */
959
960 fprintf(new, "\n/* End of config.h */\n");
961 (void)fclose(new);
962 return 0;
963 }
964
965 /* End of buildconfig.c */