Fix detection of 32b platform at build time. Bug 2405
[exim.git] / src / src / buildconfig.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
059ec3d9
PH
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
c6c2dc1d
PH
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.
b1c749bb
PH
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.
059ec3d9
PH
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>
02c30a32
JH
39#include <sys/time.h>
40#include <poll.h>
059ec3d9
PH
41#include <pwd.h>
42#include <grp.h>
43
44typedef struct {
1ba28e2b 45 const char *name;
059ec3d9
PH
46 int *flag;
47} have_item;
48
49typedef struct {
1ba28e2b 50 const char *name;
059ec3d9
PH
51 char *data;
52} save_item;
53
1ba28e2b 54static const char *db_opts[] = { "", "USE_DB", "USE_GDBM", "USE_TDB" };
059ec3d9
PH
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{
b1c749bb 104off_t test_off_t = 0;
c6c2dc1d 105time_t test_time_t = 0;
bb07bcd3 106ino_t test_ino_t;
b3c261f7 107#if ! (__STDC_VERSION__ >= 199901L)
73a46702 108size_t test_size_t = 0;
17c76198 109ssize_t test_ssize_t = 0;
73a46702 110unsigned long test_ulong_t = 0L;
74d8288d 111unsigned int test_uint_t = 0;
b3c261f7 112#endif
73a46702 113long test_long_t = 0;
26dd3aa0 114long long test_longlong_t = 0;
74d8288d 115int test_int_t = 0;
059ec3d9
PH
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
b1c749bb
PH
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");
73a46702 158if (sizeof(test_off_t) > sizeof(test_long_t))
bb07bcd3 159 fprintf(new, "# define OFF_T_FMT \"%%lld\"\n");
b1c749bb 160else
bb07bcd3 161 fprintf(new, "# define OFF_T_FMT \"%%ld\"\n");
26dd3aa0
JH
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
bb07bcd3 168 fprintf(new, "# define LONGLONG_T long int\n");
c6c2dc1d
PH
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");
73a46702 177if (sizeof(test_time_t) > sizeof(test_long_t))
c6c2dc1d 178 {
bb07bcd3
JH
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");
c6c2dc1d
PH
182 }
183else
bb07bcd3
JH
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");
b1c749bb
PH
196fprintf(new, "#endif\n\n");
197
73a46702 198/* And for sizeof() results, size_t, which should with C99 be just %zu, deal
17c76198
PP
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. */
73a46702
PP
202
203#if __STDC_VERSION__ >= 199901L
204fprintf(new, "#define SIZE_T_FMT \"%%zu\"\n");
17c76198 205fprintf(new, "#define SSIZE_T_FMT \"%%zd\"\n");
73a46702 206#else
73a46702
PP
207if (sizeof(test_size_t) > sizeof (test_ulong_t))
208 fprintf(new, "#define SIZE_T_FMT \"%%llu\"\n");
74d8288d 209else if (sizeof(test_size_t) > sizeof (test_uint_t))
73a46702 210 fprintf(new, "#define SIZE_T_FMT \"%%lu\"\n");
74d8288d
JH
211else
212 fprintf(new, "#define SIZE_T_FMT \"%%u\"\n");
213
17c76198
PP
214if (sizeof(test_ssize_t) > sizeof(test_long_t))
215 fprintf(new, "#define SSIZE_T_FMT \"%%lld\"\n");
74d8288d 216else if (sizeof(test_ssize_t) > sizeof(test_int_t))
17c76198 217 fprintf(new, "#define SSIZE_T_FMT \"%%ld\"\n");
74d8288d
JH
218else
219 fprintf(new, "#define SSIZE_T_FMT \"%%d\"\n");
73a46702
PP
220#endif
221
b1c749bb 222/* Now search the makefile for certain settings */
059ec3d9
PH
223
224base = fopen("Makefile", "rb");
225if (base == NULL)
226 {
227 printf("*** Buildconfig: failed to open Makefile\n");
f1e894f3 228 (void)fclose(new);
059ec3d9
PH
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
2548ba04
PH
332if (strcmp(cc, "gcc") == 0 &&
333 (strstr(ostype, "IRIX") != NULL || strstr(ostype, "AIX") != NULL))
059ec3d9
PH
334 {
335 fprintf(new, "\n/* This switch includes the code to fix the inet_ntoa() */");
2548ba04 336 fprintf(new, "\n/* bug when using gcc on an IRIX or AIX system. */");
059ec3d9
PH
337 fprintf(new, "\n#define USE_INET_NTOA_FIX");
338 }
339
340fprintf(new, "\n");
f1e894f3 341(void)fclose(base);
059ec3d9
PH
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");
f1e894f3 350 (void)fclose(new);
059ec3d9
PH
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
97d17305
JH
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
059ec3d9
PH
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;
10385c15 413 int uid_not_set = 0;
059ec3d9
PH
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;
10385c15 468 uid_not_set = 1;
059ec3d9
PH
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
10385c15
PP
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) ||
655c5895
PP
567 ((username != NULL) && (
568 (strcmp(username, "root") == 0) ||
569 (strcmp(username, "toor") == 0) )))
10385c15
PP
570 {
571 printf("\n*** Exim's internal user must not be root.\n\n");
572 return 1;
573 }
574
059ec3d9
PH
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
35edf2ff
PH
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. */
059ec3d9 592
35edf2ff
PH
593 if (strcmp(name, "CONFIGURE_OWNER") == 0 ||
594 strcmp(name, "CONFIGURE_GROUP") == 0)
059ec3d9 595 {
8e669ac1 596 int isgroup = name[10] == 'G';
059ec3d9 597 uid_t uid = 0;
8e669ac1 598 gid_t gid = 0;
1ba28e2b
PP
599 const char *s;
600 const char *username = NULL;
601 const char *user = getenv(name);
059ec3d9
PH
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 {
35edf2ff 615 printf("\n*** %s contains the control character 0x%02X in "
059ec3d9 616 "one of the files\n in the \"Local\" directory. Please review "
35edf2ff 617 "your build-time\n configuration.\n\n", name, *s);
059ec3d9
PH
618 return 1;
619 }
620 }
621
622 /* Numeric uid given */
623
624 if (user[strspn(user, "0123456789")] == 0)
625 {
35edf2ff
PH
626 if (isgroup)
627 gid = (gid_t)atoi(user);
8e669ac1 628 else
35edf2ff 629 uid = (uid_t)atoi(user);
059ec3d9
PH
630 }
631
35edf2ff 632 /* Name given. Normally, we look up the uid or gid right away. However,
059ec3d9
PH
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 }
1ba28e2b 642else if (isgroup)
35edf2ff
PH
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
059ec3d9
PH
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 }
059ec3d9
PH
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)
35edf2ff
PH
672 {
673 if (isgroup)
674 fprintf(new, "#define CONFIGURE_GROUPNAME \"%s\"\n", username);
8e669ac1 675 else
35edf2ff
PH
676 fprintf(new, "#define CONFIGURE_OWNERNAME \"%s\"\n", username);
677 }
8e669ac1 678
35edf2ff
PH
679 if (isgroup)
680 fprintf(new, "#define CONFIGURE_GROUP %d\n", (int)gid);
8e669ac1 681 else
35edf2ff 682 fprintf(new, "#define CONFIGURE_OWNER %d\n", (int)uid);
059ec3d9
PH
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;
926e1192 699 int i, j;
059ec3d9
PH
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
926e1192 707 for (i = 1, j = 0; i <= count; list++, i++)
059ec3d9
PH
708 {
709 char name[64];
8e669ac1 710
059ec3d9
PH
711 p = list;
712 while (*list != 0 && *list != ':') list++;
713 strncpy(name, p, list-p);
714 name[list-p] = 0;
8e669ac1 715
926e1192
PH
716 if (name[0] == 0)
717 {
8e669ac1
PH
718 continue;
719 }
926e1192 720 else if (name[strspn(name, "0123456789")] == 0)
059ec3d9 721 {
926e1192 722 vector[j++] = (uid_t)atoi(name);
059ec3d9
PH
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 }
926e1192 734 vector[j++] = pw->pw_uid;
059ec3d9
PH
735 }
736 }
926e1192
PH
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");
7cc29763 740 free(vector);
059ec3d9
PH
741 }
742 continue;
743 }
744
6f1b3e5d
JH
745 /* WITH_CONTENT_SCAN is another special case: it must be set if it or
746 EXPERIMENTAL_DCC is set. */
c6e692d7
PH
747
748 if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
749 {
750 char *wcs = getenv("WITH_CONTENT_SCAN");
6a8f9482 751 char *dcc = getenv("EXPERIMENTAL_DCC");
03d5892b
JH
752 fprintf(new, wcs || dcc
753 ? "#define WITH_CONTENT_SCAN yes\n"
754 : "/* WITH_CONTENT_SCAN not set */\n");
c6e692d7 755 continue;
8e669ac1 756 }
c6e692d7 757
01603eec 758 /* DISABLE_DKIM is special; must be forced if DISABLE_TLS */
f444c2c7
JH
759 if (strcmp(name, "DISABLE_DKIM") == 0)
760 {
761 char *d_dkim = getenv("DISABLE_DKIM");
01603eec 762 char *notls = getenv("DISABLE_TLS");
f444c2c7
JH
763
764 if (d_dkim)
765 fprintf(new, "#define DISABLE_DKIM yes\n");
01603eec 766 else if (notls)
f444c2c7
JH
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
059ec3d9
PH
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 ||
7766a4f0 808 strcmp(value, "RADIUSCLIENTNEW") == 0 ||
059ec3d9
PH
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 }
ae20c809
JH
843 else
844 {
845 strncpy(buffer, ss, sizeof(buffer));
846 buffer[sizeof(buffer)-1] = 0;
847 }
059ec3d9
PH
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
a7cbbf50
PP
860 /* Timezone values HEADERS_CHARSET, TCP_WRAPPERS_DAEMON_NAME and
861 WHITELIST_D_MACROS get quoted */
059ec3d9
PH
862
863 else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
5dc43717 864 strcmp(name, "TCP_WRAPPERS_DAEMON_NAME") == 0||
a7cbbf50 865 strcmp(name, "HEADERS_CHARSET") == 0||
2c17bb02 866 strcmp(name, "WHITELIST_D_MACROS") == 0)
059ec3d9
PH
867 fprintf(new, "\"%s\"\n", value);
868
2c17bb02
PP
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 */
54c90be1
PP
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) ||
2c17bb02
PP
895 (strcmp(name, "EXIM_SERVER_DH_BITS_PRE2_12") == 0))
896 {
897 long nv;
898 char *end;
899 nv = strtol(value, &end, 10);
54c90be1 900 if (end != value && *end == '\0' && nv >= 512 && nv < 500000)
2c17bb02
PP
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
059ec3d9
PH
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
f1e894f3 952(void)fclose(base);
059ec3d9
PH
953
954/* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
955defined. */
956
957if (have_auth)
059ec3d9
PH
958 if (!support_crypteq) fprintf(new, "/* Force SUPPORT_CRYPTEQ for AUTH */\n"
959 "#define SUPPORT_CRYPTEQ\n");
059ec3d9 960
02c30a32
JH
961/* Check poll() for timer functionality.
962Some OS' have released with it broken. */
963
964 {
965 struct timeval before, after;
02c30a32
JH
966 size_t us;
967
968 gettimeofday(&before, NULL);
ed2b3ee0 969 (void) poll(NULL, 0, 500);
02c30a32
JH
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
059ec3d9
PH
979/* End off */
980
981fprintf(new, "\n/* End of config.h */\n");
f1e894f3 982(void)fclose(new);
059ec3d9
PH
983return 0;
984}
985
986/* End of buildconfig.c */