Build: probe for broken poll() timing implementation
[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;
74d8288d 114int test_int_t = 0;
059ec3d9
PH
115FILE *base;
116FILE *new;
117int last_initial = 'A';
118int linecount = 0;
119int have_auth = 0;
120int in_local_makefile = 0;
121int use_which_db = 0;
122int use_which_db_in_local_makefile = 0;
123int support_crypteq = 0;
124char buffer[1024];
125
126if (argc != 1)
127 {
128 printf("*** Buildconfig: called with incorrect arguments\n");
129 exit(1);
130 }
131
132new = fopen("config.h", "wb");
133if (new == NULL)
134 {
135 printf("*** Buildconfig: failed to open config.h for output\n");
136 exit(1);
137 }
138
139printf("Building configuration file config.h\n");
140
141fprintf(new, "/*************************************************\n");
142fprintf(new, "* Configuration header for Exim *\n");
143fprintf(new, "*************************************************/\n\n");
144
145fprintf(new, "/* This file was automatically generated from Makefile and "
146 "config.h.defaults,\n");
147fprintf(new, "using values specified in the configuration file Local/Makefile.\n");
148fprintf(new, "Do not edit it. Instead, edit Local/Makefile and "
149 "rerun make. */\n\n");
150
b1c749bb
PH
151/* First, deal with the printing format for off_t variables. We assume that if
152the size of off_t is greater than 4, "%lld" will be available as a format for
153printing long long variables, and there will be support for the long long type.
154This assumption is known to be OK for the common operating systems. */
155
156fprintf(new, "#ifndef OFF_T_FMT\n");
73a46702 157if (sizeof(test_off_t) > sizeof(test_long_t))
b1c749bb 158 {
bb07bcd3
JH
159 fprintf(new, "# define OFF_T_FMT \"%%lld\"\n");
160 fprintf(new, "# define LONGLONG_T long long int\n");
b1c749bb
PH
161 }
162else
163 {
bb07bcd3
JH
164 fprintf(new, "# define OFF_T_FMT \"%%ld\"\n");
165 fprintf(new, "# define LONGLONG_T long int\n");
c6c2dc1d
PH
166 }
167fprintf(new, "#endif\n\n");
168
169/* Now do the same thing for time_t variables. If the length is greater than
1704, we want to assume long long support (even if off_t was less than 4). If the
171length is 4 or less, we can leave LONGLONG_T to whatever was defined above for
172off_t. */
173
174fprintf(new, "#ifndef TIME_T_FMT\n");
73a46702 175if (sizeof(test_time_t) > sizeof(test_long_t))
c6c2dc1d 176 {
bb07bcd3
JH
177 fprintf(new, "# define TIME_T_FMT \"%%lld\"\n");
178 fprintf(new, "# undef LONGLONG_T\n");
179 fprintf(new, "# define LONGLONG_T long long int\n");
c6c2dc1d
PH
180 }
181else
bb07bcd3
JH
182 fprintf(new, "# define TIME_T_FMT \"%%ld\"\n");
183fprintf(new, "#endif\n\n");
184
185fprintf(new, "#ifndef INO_T_FMT\n");
186if (sizeof(test_ino_t) > sizeof(test_long_t))
187 fprintf(new, "# define INO_T_FMT \"%%llu\"\n");
188else
189 fprintf(new, "# define INO_T_FMT \"%%lu\"\n");
190fprintf(new, "#endif\n\n");
191
192fprintf(new, "#ifndef PID_T_FMT\n");
193fprintf(new, "# define PID_T_FMT \"%%lu\"\n");
b1c749bb
PH
194fprintf(new, "#endif\n\n");
195
73a46702 196/* And for sizeof() results, size_t, which should with C99 be just %zu, deal
17c76198
PP
197with C99 not being ubiquitous yet. Unfortunately. Assume ssize_t is same
198size as size_t on C99; if someone comes up with a version where it's not, fix
199it then. */
73a46702
PP
200
201#if __STDC_VERSION__ >= 199901L
202fprintf(new, "#define SIZE_T_FMT \"%%zu\"\n");
17c76198 203fprintf(new, "#define SSIZE_T_FMT \"%%zd\"\n");
73a46702 204#else
73a46702
PP
205if (sizeof(test_size_t) > sizeof (test_ulong_t))
206 fprintf(new, "#define SIZE_T_FMT \"%%llu\"\n");
74d8288d 207else if (sizeof(test_size_t) > sizeof (test_uint_t))
73a46702 208 fprintf(new, "#define SIZE_T_FMT \"%%lu\"\n");
74d8288d
JH
209else
210 fprintf(new, "#define SIZE_T_FMT \"%%u\"\n");
211
17c76198
PP
212if (sizeof(test_ssize_t) > sizeof(test_long_t))
213 fprintf(new, "#define SSIZE_T_FMT \"%%lld\"\n");
74d8288d 214else if (sizeof(test_ssize_t) > sizeof(test_int_t))
17c76198 215 fprintf(new, "#define SSIZE_T_FMT \"%%ld\"\n");
74d8288d
JH
216else
217 fprintf(new, "#define SSIZE_T_FMT \"%%d\"\n");
73a46702
PP
218#endif
219
b1c749bb 220/* Now search the makefile for certain settings */
059ec3d9
PH
221
222base = fopen("Makefile", "rb");
223if (base == NULL)
224 {
225 printf("*** Buildconfig: failed to open Makefile\n");
f1e894f3 226 (void)fclose(new);
059ec3d9
PH
227 exit(1);
228 }
229
230errno_quota[0] = 0; /* no over-riding value set */
231ostype[0] = 0; /* just in case */
232cc[0] = 0;
233
234while (fgets(buffer, sizeof(buffer), base) != NULL)
235 {
236 int i;
237 have_item *h;
238 save_item *s;
239 char *p = buffer + (int)strlen(buffer);
240 linecount++;
241 while (p > buffer && isspace((unsigned char)p[-1])) p--;
242 *p = 0;
243 p = buffer;
244 while (isspace((unsigned char)*p)) p++;
245
246 /* Notice when we hit the user's makefile */
247
248 if (strcmp(p, "# From Local/Makefile") == 0)
249 {
250 in_local_makefile = 1;
251 continue;
252 }
253
254 /* Remember the last DB option setting. If we hit two in the user's
255 Makefile, complain. */
256
257 for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
258 {
259 int len = (int)strlen(db_opts[i]);
260 if (strncmp(p, db_opts[i], len) == 0 && (p[len] == ' ' || p[len] == '='))
261 {
262 if (in_local_makefile)
263 {
264 if (use_which_db_in_local_makefile)
265 {
266 printf("*** Only one of USE_DB, USE_GDBM, or USE_TDB should be "
267 "defined in Local/Makefile\n");
268 exit(1);
269 }
270 use_which_db_in_local_makefile = 1;
271 }
272 use_which_db = i;
273 break;
274 }
275 }
276 if (i < sizeof(db_opts)/sizeof(char *)) continue;
277
278 /* Items where we just save a boolean */
279
280 for (h = have_list; h->name != NULL; h++)
281 {
282 int len = (int)strlen(h->name);
283 if (strncmp(p, h->name, len) == 0)
284 {
285 p += len;
286 while (isspace((unsigned char)*p)) p++;
287 if (*p++ != '=')
288 {
289 printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
290 exit(1);
291 }
292 while (isspace((unsigned char)*p)) p++;
293 if (strcmp(p, "YES") == 0 || strcmp(p, "yes") == 0) *(h->flag) = 1;
294 else *(h->flag) = 0; /* Must reset in case multiple instances */
295 break;
296 }
297 }
298
299 if (h->name != NULL) continue;
300
301 /* Items where we save the complete string */
302
303 for (s = save_list; s->name != NULL; s++)
304 {
305 int len = (int)strlen(s->name);
306 if (strncmp(p, s->name, len) == 0)
307 {
308 p += len;
309 while (isspace((unsigned char)*p)) p++;
310 if (*p++ != '=')
311 {
312 printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
313 exit(1);
314 }
315 while (isspace((unsigned char)*p)) p++;
316 strcpy(s->data, p);
317 }
318 }
319 }
320
321fprintf(new, "#define HAVE_IPV6 %s\n",
322 have_ipv6? "TRUE" : "FALSE");
323
324fprintf(new, "#define HAVE_ICONV %s\n",
325 have_iconv? "TRUE" : "FALSE");
326
327if (errno_quota[0] != 0)
328 fprintf(new, "\n#define ERRNO_QUOTA %s\n", errno_quota);
329
2548ba04
PH
330if (strcmp(cc, "gcc") == 0 &&
331 (strstr(ostype, "IRIX") != NULL || strstr(ostype, "AIX") != NULL))
059ec3d9
PH
332 {
333 fprintf(new, "\n/* This switch includes the code to fix the inet_ntoa() */");
2548ba04 334 fprintf(new, "\n/* bug when using gcc on an IRIX or AIX system. */");
059ec3d9
PH
335 fprintf(new, "\n#define USE_INET_NTOA_FIX");
336 }
337
338fprintf(new, "\n");
f1e894f3 339(void)fclose(base);
059ec3d9
PH
340
341
342/* Now handle the macros listed in the defaults */
343
344base = fopen("../src/config.h.defaults", "rb");
345if (base == NULL)
346 {
347 printf("*** Buildconfig: failed to open ../src/config.h.defaults\n");
f1e894f3 348 (void)fclose(new);
059ec3d9
PH
349 exit(1);
350 }
351
352while (fgets(buffer, sizeof(buffer), base) != NULL)
353 {
354 int i;
355 char name[256];
356 char *value;
357 char *p = buffer;
358 char *q = name;
359
360 while (*p == ' ' || *p == '\t') p++;
361
97d17305
JH
362 if (strncmp(p, "#ifdef ", 7) == 0
363 || strncmp(p, "#ifndef ", 8) == 0
364 || strncmp(p, "#if ", 4) == 0
365 || strncmp(p, "#endif", 6) == 0
366 )
367 {
368 fputs(buffer, new);
369 continue;
370 }
371
059ec3d9
PH
372 if (strncmp(p, "#define ", 8) != 0) continue;
373
374 p += 8;
375 while (*p == ' ' || *p == '\t') p++;
376
377 if (*p < last_initial) fprintf(new, "\n");
378 last_initial = *p;
379
380 while (*p && (isalnum((unsigned char)*p) || *p == '_')) *q++ = *p++;
381 *q = 0;
382
383 /* USE_DB, USE_GDBM, and USE_TDB are special cases. We want to have only
384 one of them set. The scan of the Makefile has saved which was the last one
385 encountered. */
386
387 for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
388 {
389 if (strcmp(name, db_opts[i]) == 0)
390 {
391 if (use_which_db == i)
392 fprintf(new, "#define %s %.*syes\n", db_opts[i],
393 21 - (int)strlen(db_opts[i]), " ");
394 else
395 fprintf(new, "/* %s not set */\n", name);
396 break;
397 }
398 }
399 if (i < sizeof(db_opts)/sizeof(char *)) continue;
400
401 /* EXIM_USER is a special case. We look in the environment for EXIM_USER or
402 EXIM_UID (the latter for backward compatibility with Exim 3). If the value is
403 not numeric, we look up the user, and default the GID if found. Otherwise,
404 EXIM_GROUP or EXIM_GID must be in the environment. */
405
406 if (strcmp(name, "EXIM_UID") == 0)
407 {
408 uid_t uid = 0;
409 gid_t gid = 0;
410 int gid_set = 0;
10385c15 411 int uid_not_set = 0;
059ec3d9
PH
412 char *username = NULL;
413 char *groupname = NULL;
414 char *s;
415 char *user = getenv("EXIM_USER");
416 char *group = getenv("EXIM_GROUP");
417
418 if (user == NULL) user = getenv("EXIM_UID");
419 if (group == NULL) group = getenv("EXIM_GID");
420
421 if (user == NULL)
422 {
423 printf("\n*** EXIM_USER has not been defined in any of the Makefiles in "
424 "the\n \"Local\" directory. Please review your build-time "
425 "configuration.\n\n");
426 return 1;
427 }
428
429 while (isspace((unsigned char)(*user))) user++;
430 if (*user == 0)
431 {
432 printf("\n*** EXIM_USER is defined as an empty string in one of the "
433 "files\n in the \"Local\" directory. Please review your build-time"
434 "\n configuration.\n\n");
435 return 1;
436 }
437
438 for (s = user; *s != 0; s++)
439 {
440 if (iscntrl((unsigned char)(*s)))
441 {
442 printf("\n*** EXIM_USER contains the control character 0x%02X in one "
443 "of the files\n in the \"Local\" directory. Please review your "
444 "build-time\n configuration.\n\n", *s);
445 return 1;
446 }
447 }
448
449 /* Numeric uid given */
450
451 if (user[strspn(user, "0123456789")] == 0)
452 {
453 uid = (uid_t)atoi(user);
454 }
455
456 /* User name given. Normally, we look up the uid right away. However,
457 people building binary distributions sometimes want to retain the name till
458 runtime. This is supported if the name begins "ref:". */
459
460 else if (strncmp(user, "ref:", 4) == 0)
461 {
462 user += 4;
463 while (isspace(*user)) user++;
464 username = user;
465 gid_set = 1;
10385c15 466 uid_not_set = 1;
059ec3d9
PH
467 }
468
469 else
470 {
471 struct passwd *pw = getpwnam(user);
472 if (pw == NULL)
473 {
474 printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
475 "exist.\n Please review your build-time configuration.\n\n",
476 user);
477 return 1;
478 }
479
480 uid = pw->pw_uid;
481 gid = pw->pw_gid;
482 gid_set = 1;
483 }
484
485 /* Use explicit group if set. */
486
487 if (group != NULL)
488 {
489 while (isspace((unsigned char)(*group))) group++;
490 if (*group == 0)
491 {
492 printf("\n*** EXIM_GROUP is defined as an empty string in one of "
493 "the files in the\n \"Local\" directory. ");
494 if (gid_set)
495 {
496 printf("If you want the Exim group to be taken from the\n "
497 "password data for the Exim user, just remove the EXIM_GROUP "
498 "setting.\n Otherwise, p");
499 }
500 else printf("EXIM_USER is defined numerically, so there is no"
501 "\n default for EXIM_GROUP and you must set it explicitly.\n P");
502 printf("lease review your build-time configuration.\n\n");
503 return 1;
504 }
505
506 for (s = group; *s != 0; s++)
507 {
508 if (iscntrl((unsigned char)(*s)))
509 {
510 printf("\n*** EXIM_GROUP contains the control character 0x%02X in one "
511 "of the files\n in the \"Local\" directory. Please review your "
512 "build-time\n configuration.\n\n", *s);
513 return 1;
514 }
515 }
516
517 /* Group name given. This may be by reference or to be looked up now,
518 as for user. */
519
520 if (strncmp(group, "ref:", 4) == 0)
521 {
522 group += 4;
523 while (isspace(*group)) group++;
524 groupname = group;
525 }
526
527 else if (username != NULL)
528 {
529 groupname = group;
530 }
531
532 else if (group[strspn(group, "0123456789")] == 0)
533 {
534 gid = (gid_t)atoi(group);
535 }
536
537 else
538 {
539 struct group *gr = getgrnam(group);
540 if (gr == NULL)
541 {
542 printf("\n*** Group \"%s\" (specified in one of the Makefiles) does "
543 "not exist.\n Please review your build-time configuration.\n\n",
544 group);
545 return 1;
546 }
547 gid = gr->gr_gid;
548 }
549 }
550
551 /* Else trouble unless found in passwd file with user */
552
553 else if (!gid_set)
554 {
555 printf("\n*** No group set for Exim. Please review your build-time "
556 "configuration.\n\n");
557 return 1;
558 }
559
10385c15
PP
560 /* security sanity checks
561 if ref: is being used, we can never be sure, but we can take reasonable
562 steps to filter out the most obvious ones. */
563
564 if ((!uid_not_set && uid == 0) ||
655c5895
PP
565 ((username != NULL) && (
566 (strcmp(username, "root") == 0) ||
567 (strcmp(username, "toor") == 0) )))
10385c15
PP
568 {
569 printf("\n*** Exim's internal user must not be root.\n\n");
570 return 1;
571 }
572
059ec3d9
PH
573 /* Output user and group names or uid/gid. When names are set, uid/gid
574 are set to zero but will be replaced at runtime. */
575
576 if (username != NULL)
577 fprintf(new, "#define EXIM_USERNAME \"%s\"\n", username);
578 if (groupname != NULL)
579 fprintf(new, "#define EXIM_GROUPNAME \"%s\"\n", groupname);
580
581 fprintf(new, "#define EXIM_UID %d\n", (int)uid);
582 fprintf(new, "#define EXIM_GID %d\n", (int)gid);
583 continue;
584 }
585
35edf2ff
PH
586 /* CONFIGURE_OWNER and CONFIGURE_GROUP are special cases. We look in the
587 environment for first. If the value is not numeric, we look up the user or
588 group. A lot of this code is similar to that for EXIM_USER, but it's easier
589 to keep it separate. */
059ec3d9 590
35edf2ff
PH
591 if (strcmp(name, "CONFIGURE_OWNER") == 0 ||
592 strcmp(name, "CONFIGURE_GROUP") == 0)
059ec3d9 593 {
8e669ac1 594 int isgroup = name[10] == 'G';
059ec3d9 595 uid_t uid = 0;
8e669ac1 596 gid_t gid = 0;
1ba28e2b
PP
597 const char *s;
598 const char *username = NULL;
599 const char *user = getenv(name);
059ec3d9
PH
600
601 if (user == NULL) user = "";
602 while (isspace((unsigned char)(*user))) user++;
603 if (*user == 0)
604 {
605 fprintf(new, "/* %s not set */\n", name);
606 continue;
607 }
608
609 for (s = user; *s != 0; s++)
610 {
611 if (iscntrl((unsigned char)(*s)))
612 {
35edf2ff 613 printf("\n*** %s contains the control character 0x%02X in "
059ec3d9 614 "one of the files\n in the \"Local\" directory. Please review "
35edf2ff 615 "your build-time\n configuration.\n\n", name, *s);
059ec3d9
PH
616 return 1;
617 }
618 }
619
620 /* Numeric uid given */
621
622 if (user[strspn(user, "0123456789")] == 0)
623 {
35edf2ff
PH
624 if (isgroup)
625 gid = (gid_t)atoi(user);
8e669ac1 626 else
35edf2ff 627 uid = (uid_t)atoi(user);
059ec3d9
PH
628 }
629
35edf2ff 630 /* Name given. Normally, we look up the uid or gid right away. However,
059ec3d9
PH
631 people building binary distributions sometimes want to retain the name till
632 runtime. This is supported if the name begins "ref:". */
633
634 else if (strncmp(user, "ref:", 4) == 0)
635 {
636 user += 4;
637 while (isspace(*user)) user++;
638 username = user;
639 }
1ba28e2b 640else if (isgroup)
35edf2ff
PH
641 {
642 struct group *gr = getgrnam(user);
643 if (gr == NULL)
644 {
645 printf("\n*** Group \"%s\" (specified in one of the Makefiles) does not "
646 "exist.\n Please review your build-time configuration.\n\n",
647 user);
648 return 1;
649 }
650 gid = gr->gr_gid;
651 }
652
059ec3d9
PH
653 else
654 {
655 struct passwd *pw = getpwnam(user);
656 if (pw == NULL)
657 {
658 printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
659 "exist.\n Please review your build-time configuration.\n\n",
660 user);
661 return 1;
662 }
059ec3d9
PH
663 uid = pw->pw_uid;
664 }
665
666 /* Output user and group names or uid/gid. When names are set, uid/gid
667 are set to zero but will be replaced at runtime. */
668
669 if (username != NULL)
35edf2ff
PH
670 {
671 if (isgroup)
672 fprintf(new, "#define CONFIGURE_GROUPNAME \"%s\"\n", username);
8e669ac1 673 else
35edf2ff
PH
674 fprintf(new, "#define CONFIGURE_OWNERNAME \"%s\"\n", username);
675 }
8e669ac1 676
35edf2ff
PH
677 if (isgroup)
678 fprintf(new, "#define CONFIGURE_GROUP %d\n", (int)gid);
8e669ac1 679 else
35edf2ff 680 fprintf(new, "#define CONFIGURE_OWNER %d\n", (int)uid);
059ec3d9
PH
681 continue;
682 }
683
684 /* FIXED_NEVER_USERS is another special case. Look up the uid values and
685 create suitable initialization data for a vector. */
686
687 if (strcmp(name, "FIXED_NEVER_USERS") == 0)
688 {
689 char *list = getenv("FIXED_NEVER_USERS");
690 if (list == NULL)
691 {
692 fprintf(new, "#define FIXED_NEVER_USERS 0\n");
693 }
694 else
695 {
696 int count = 1;
926e1192 697 int i, j;
059ec3d9
PH
698 uid_t *vector;
699 char *p = list;
700 while (*p != 0) if (*p++ == ':') count++;
701
702 vector = malloc((count+1) * sizeof(uid_t));
703 vector[0] = (uid_t)count;
704
926e1192 705 for (i = 1, j = 0; i <= count; list++, i++)
059ec3d9
PH
706 {
707 char name[64];
8e669ac1 708
059ec3d9
PH
709 p = list;
710 while (*list != 0 && *list != ':') list++;
711 strncpy(name, p, list-p);
712 name[list-p] = 0;
8e669ac1 713
926e1192
PH
714 if (name[0] == 0)
715 {
8e669ac1
PH
716 continue;
717 }
926e1192 718 else if (name[strspn(name, "0123456789")] == 0)
059ec3d9 719 {
926e1192 720 vector[j++] = (uid_t)atoi(name);
059ec3d9
PH
721 }
722 else
723 {
724 struct passwd *pw = getpwnam(name);
725 if (pw == NULL)
726 {
727 printf("\n*** User \"%s\" (specified for FIXED_NEVER_USERS in one of the Makefiles) does not "
728 "exist.\n Please review your build-time configuration.\n\n",
729 name);
730 return 1;
731 }
926e1192 732 vector[j++] = pw->pw_uid;
059ec3d9
PH
733 }
734 }
926e1192
PH
735 fprintf(new, "#define FIXED_NEVER_USERS %d", j);
736 for (i = 0; i < j; i++) fprintf(new, ", %d", (unsigned int)vector[i]);
737 fprintf(new, "\n");
7cc29763 738 free(vector);
059ec3d9
PH
739 }
740 continue;
741 }
742
6f1b3e5d
JH
743 /* WITH_CONTENT_SCAN is another special case: it must be set if it or
744 EXPERIMENTAL_DCC is set. */
c6e692d7
PH
745
746 if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
747 {
748 char *wcs = getenv("WITH_CONTENT_SCAN");
6a8f9482 749 char *dcc = getenv("EXPERIMENTAL_DCC");
03d5892b
JH
750 fprintf(new, wcs || dcc
751 ? "#define WITH_CONTENT_SCAN yes\n"
752 : "/* WITH_CONTENT_SCAN not set */\n");
c6e692d7 753 continue;
8e669ac1 754 }
c6e692d7 755
f444c2c7
JH
756 /* DISABLE_DKIM is special; must be forced if no SUPPORT_TLS */
757 if (strcmp(name, "DISABLE_DKIM") == 0)
758 {
759 char *d_dkim = getenv("DISABLE_DKIM");
760 char *tls = getenv("SUPPORT_TLS");
761
762 if (d_dkim)
763 fprintf(new, "#define DISABLE_DKIM yes\n");
764 else if (!tls)
765 fprintf(new, "#define DISABLE_DKIM yes /* forced by lack of TLS */\n");
766 else
767 fprintf(new, "/* DISABLE_DKIM not set */\n");
768 continue;
769 }
770
059ec3d9
PH
771 /* Otherwise, check whether a value exists in the environment. Remember if
772 it is an AUTH setting or SUPPORT_CRYPTEQ. */
773
774 if ((value = getenv(name)) != NULL)
775 {
776 int len;
777 len = 21 - (int)strlen(name);
778
779 if (strncmp(name, "AUTH_", 5) == 0) have_auth = 1;
780 if (strncmp(name, "SUPPORT_CRYPTEQ", 15) == 0) support_crypteq = 1;
781
782 /* The text value of LDAP_LIB_TYPE refers to a macro that gets set. */
783
784 if (strcmp(name, "LDAP_LIB_TYPE") == 0)
785 {
786 if (strcmp(value, "NETSCAPE") == 0 ||
787 strcmp(value, "UMICHIGAN") == 0 ||
788 strcmp(value, "OPENLDAP1") == 0 ||
789 strcmp(value, "OPENLDAP2") == 0 ||
790 strcmp(value, "SOLARIS") == 0 ||
791 strcmp(value, "SOLARIS7") == 0) /* Compatibility */
792 {
793 fprintf(new, "#define LDAP_LIB_%s\n", value);
794 }
795 else
796 {
797 printf("\n*** LDAP_LIB_TYPE=%s is not a recognized LDAP library type."
798 "\n*** Please review your build-time configuration.\n\n", value);
799 return 1;
800 }
801 }
802
803 else if (strcmp(name, "RADIUS_LIB_TYPE") == 0)
804 {
805 if (strcmp(value, "RADIUSCLIENT") == 0 ||
7766a4f0 806 strcmp(value, "RADIUSCLIENTNEW") == 0 ||
059ec3d9
PH
807 strcmp(value, "RADLIB") == 0)
808 {
809 fprintf(new, "#define RADIUS_LIB_%s\n", value);
810 }
811 else
812 {
813 printf("\n*** RADIUS_LIB_TYPE=%s is not a recognized RADIUS library type."
814 "\n*** Please review your build-time configuration.\n\n", value);
815 return 1;
816 }
817 }
818
819 /* Other macros get set to the environment value. */
820
821 else
822 {
823 fprintf(new, "#define %s ", name);
824 while(len-- > 0) fputc(' ', new);
825
826 /* LOG_FILE_PATH is now messy because it can be a path containing %s or
827 it can be "syslog" or ":syslog" or "syslog:path" or even "path:syslog". */
828
829 if (strcmp(name, "LOG_FILE_PATH") == 0)
830 {
831 char *ss = value;
832 for(;;)
833 {
834 char *pp;
835 char *sss = strchr(ss, ':');
836 if (sss != NULL)
837 {
838 strncpy(buffer, ss, sss-ss);
839 buffer[sss-ss] = 0; /* For empty case */
840 }
ae20c809
JH
841 else
842 {
843 strncpy(buffer, ss, sizeof(buffer));
844 buffer[sizeof(buffer)-1] = 0;
845 }
059ec3d9
PH
846 pp = buffer + (int)strlen(buffer);
847 while (pp > buffer && isspace((unsigned char)pp[-1])) pp--;
848 *pp = 0;
849 if (buffer[0] != 0 && strcmp(buffer, "syslog") != 0)
850 check_percent_ess(buffer, name);
851 if (sss == NULL) break;
852 ss = sss + 1;
853 while (isspace((unsigned char)*ss)) ss++;
854 }
855 fprintf(new, "\"%s\"\n", value);
856 }
857
a7cbbf50
PP
858 /* Timezone values HEADERS_CHARSET, TCP_WRAPPERS_DAEMON_NAME and
859 WHITELIST_D_MACROS get quoted */
059ec3d9
PH
860
861 else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
5dc43717 862 strcmp(name, "TCP_WRAPPERS_DAEMON_NAME") == 0||
a7cbbf50 863 strcmp(name, "HEADERS_CHARSET") == 0||
2c17bb02 864 strcmp(name, "WHITELIST_D_MACROS") == 0)
059ec3d9
PH
865 fprintf(new, "\"%s\"\n", value);
866
2c17bb02
PP
867 /* GnuTLS constants; first is for debugging, others are tuning */
868
869 /* less than 0 is not-active; 0-9 are normal, API suggests higher
870 taken without problems */
871 else if (strcmp(name, "EXIM_GNUTLS_LIBRARY_LOG_LEVEL") == 0)
872 {
873 long nv;
874 char *end;
875 nv = strtol(value, &end, 10);
876 if (end != value && *end == '\0' && nv >= -1 && nv <= 100)
877 {
878 fprintf(new, "%s\n", value);
879 }
880 else
881 {
882 printf("Value of %s should be -1..9\n", name);
883 return 1;
884 }
885 }
886
887 /* how many bits Exim, as a client, demands must be in D-H */
54c90be1
PP
888 /* 1024 is a historical figure; some sites actually use lower, so we
889 permit the value to be lowered "dangerously" low, but not "insanely"
890 low. Though actually, 1024 is becoming "dangerous". */
891 else if ((strcmp(name, "EXIM_CLIENT_DH_MIN_MIN_BITS") == 0) ||
892 (strcmp(name, "EXIM_CLIENT_DH_DEFAULT_MIN_BITS") == 0) ||
2c17bb02
PP
893 (strcmp(name, "EXIM_SERVER_DH_BITS_PRE2_12") == 0))
894 {
895 long nv;
896 char *end;
897 nv = strtol(value, &end, 10);
54c90be1 898 if (end != value && *end == '\0' && nv >= 512 && nv < 500000)
2c17bb02
PP
899 {
900 fprintf(new, "%s\n", value);
901 }
902 else
903 {
904 printf("Unreasonable value (%s) of \"%s\".\n", value, name);
905 return 1;
906 }
907 }
908
059ec3d9
PH
909 /* For others, quote any paths and don't quote anything else */
910
911 else
912 {
913 if (value[0] == '/') fprintf(new, "\"%s\"\n", value);
914 else fprintf(new, "%s\n", value);
915 }
916 }
917 }
918
919 /* Value not defined in the environment; use the default */
920
921 else
922 {
923 char *t = p;
924 while (*p == ' ' || *p == '\t') p++;
925 if (*p != '\n') fputs(buffer, new); else
926 {
927 *t = 0;
928 if (strcmp(name, "BIN_DIRECTORY") == 0 ||
929 strcmp(name, "CONFIGURE_FILE") == 0)
930 {
931 printf("\n*** %s has not been defined in any of the Makefiles in the\n"
932 " \"Local\" directory. "
933 "Please review your build-time configuration.\n\n", name);
934 return 1;
935 }
936
937 if (strcmp(name, "TIMEZONE_DEFAULT") == 0)
938 {
939 char *tz = getenv("TZ");
940 fprintf(new, "#define TIMEZONE_DEFAULT ");
941 if (tz == NULL) fprintf(new, "NULL\n"); else
942 fprintf(new, "\"%s\"\n", tz);
943 }
944
945 else fprintf(new, "/* %s not set */\n", name);
946 }
947 }
948 }
949
f1e894f3 950(void)fclose(base);
059ec3d9
PH
951
952/* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
953defined. */
954
955if (have_auth)
956 {
957 if (!support_crypteq) fprintf(new, "/* Force SUPPORT_CRYPTEQ for AUTH */\n"
958 "#define SUPPORT_CRYPTEQ\n");
959 }
960
02c30a32
JH
961/* Check poll() for timer functionality.
962Some OS' have released with it broken. */
963
964 {
965 struct timeval before, after;
966 int rc;
967 size_t us;
968
969 gettimeofday(&before, NULL);
970 rc = poll(NULL, 0, 500);
971 gettimeofday(&after, NULL);
972
973 us = (after.tv_sec - before.tv_sec) * 1000000 +
974 (after.tv_usec - before.tv_usec);
975
976 if (us < 400000)
977 fprintf(new, "#define NO_POLL_H\n");
978 }
979
059ec3d9
PH
980/* End off */
981
982fprintf(new, "\n/* End of config.h */\n");
f1e894f3 983(void)fclose(new);
059ec3d9
PH
984return 0;
985}
986
987/* End of buildconfig.c */