tidying
[exim.git] / src / src / buildconfig.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
9242a7e8 5/* Copyright (c) University of Cambridge 1995 - 2017 */
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>
39#include <pwd.h>
40#include <grp.h>
41
42typedef struct {
1ba28e2b 43 const char *name;
059ec3d9
PH
44 int *flag;
45} have_item;
46
47typedef struct {
1ba28e2b 48 const char *name;
059ec3d9
PH
49 char *data;
50} save_item;
51
1ba28e2b 52static const char *db_opts[] = { "", "USE_DB", "USE_GDBM", "USE_TDB" };
059ec3d9
PH
53
54static int have_ipv6 = 0;
55static int have_iconv = 0;
56
57static char errno_quota[256];
58static char ostype[256];
59static char cc[256];
60
61/* If any entry is an initial substring of another, the longer one must
62appear first. */
63
64static have_item have_list[] = {
65 { "HAVE_IPV6", &have_ipv6 },
66 { "HAVE_ICONV", &have_iconv },
67 { NULL, NULL}
68};
69
70static 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,
79bomb out. */
80
81void
82check_percent_ess(char *value, char *name)
83{
84int OK = 0;
85char *p = strstr(value, "%s");
86if (p != NULL) OK = strstr(p+2, "%s") == NULL;
87if (!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
99int
100main(int argc, char **argv)
101{
b1c749bb 102off_t test_off_t = 0;
c6c2dc1d 103time_t test_time_t = 0;
bb07bcd3 104ino_t test_ino_t;
b3c261f7 105#if ! (__STDC_VERSION__ >= 199901L)
73a46702 106size_t test_size_t = 0;
17c76198 107ssize_t test_ssize_t = 0;
73a46702 108unsigned long test_ulong_t = 0L;
74d8288d 109unsigned int test_uint_t = 0;
b3c261f7 110#endif
73a46702 111long test_long_t = 0;
74d8288d 112int test_int_t = 0;
059ec3d9
PH
113FILE *base;
114FILE *new;
115int last_initial = 'A';
116int linecount = 0;
117int have_auth = 0;
118int in_local_makefile = 0;
119int use_which_db = 0;
120int use_which_db_in_local_makefile = 0;
121int support_crypteq = 0;
122char buffer[1024];
123
124if (argc != 1)
125 {
126 printf("*** Buildconfig: called with incorrect arguments\n");
127 exit(1);
128 }
129
130new = fopen("config.h", "wb");
131if (new == NULL)
132 {
133 printf("*** Buildconfig: failed to open config.h for output\n");
134 exit(1);
135 }
136
137printf("Building configuration file config.h\n");
138
139fprintf(new, "/*************************************************\n");
140fprintf(new, "* Configuration header for Exim *\n");
141fprintf(new, "*************************************************/\n\n");
142
143fprintf(new, "/* This file was automatically generated from Makefile and "
144 "config.h.defaults,\n");
145fprintf(new, "using values specified in the configuration file Local/Makefile.\n");
146fprintf(new, "Do not edit it. Instead, edit Local/Makefile and "
147 "rerun make. */\n\n");
148
b1c749bb
PH
149/* First, deal with the printing format for off_t variables. We assume that if
150the size of off_t is greater than 4, "%lld" will be available as a format for
151printing long long variables, and there will be support for the long long type.
152This assumption is known to be OK for the common operating systems. */
153
154fprintf(new, "#ifndef OFF_T_FMT\n");
73a46702 155if (sizeof(test_off_t) > sizeof(test_long_t))
b1c749bb 156 {
bb07bcd3
JH
157 fprintf(new, "# define OFF_T_FMT \"%%lld\"\n");
158 fprintf(new, "# define LONGLONG_T long long int\n");
b1c749bb
PH
159 }
160else
161 {
bb07bcd3
JH
162 fprintf(new, "# define OFF_T_FMT \"%%ld\"\n");
163 fprintf(new, "# define LONGLONG_T long int\n");
c6c2dc1d
PH
164 }
165fprintf(new, "#endif\n\n");
166
167/* Now do the same thing for time_t variables. If the length is greater than
1684, we want to assume long long support (even if off_t was less than 4). If the
169length is 4 or less, we can leave LONGLONG_T to whatever was defined above for
170off_t. */
171
172fprintf(new, "#ifndef TIME_T_FMT\n");
73a46702 173if (sizeof(test_time_t) > sizeof(test_long_t))
c6c2dc1d 174 {
bb07bcd3
JH
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");
c6c2dc1d
PH
178 }
179else
bb07bcd3
JH
180 fprintf(new, "# define TIME_T_FMT \"%%ld\"\n");
181fprintf(new, "#endif\n\n");
182
183fprintf(new, "#ifndef INO_T_FMT\n");
184if (sizeof(test_ino_t) > sizeof(test_long_t))
185 fprintf(new, "# define INO_T_FMT \"%%llu\"\n");
186else
187 fprintf(new, "# define INO_T_FMT \"%%lu\"\n");
188fprintf(new, "#endif\n\n");
189
190fprintf(new, "#ifndef PID_T_FMT\n");
191fprintf(new, "# define PID_T_FMT \"%%lu\"\n");
b1c749bb
PH
192fprintf(new, "#endif\n\n");
193
73a46702 194/* And for sizeof() results, size_t, which should with C99 be just %zu, deal
17c76198
PP
195with C99 not being ubiquitous yet. Unfortunately. Assume ssize_t is same
196size as size_t on C99; if someone comes up with a version where it's not, fix
197it then. */
73a46702
PP
198
199#if __STDC_VERSION__ >= 199901L
200fprintf(new, "#define SIZE_T_FMT \"%%zu\"\n");
17c76198 201fprintf(new, "#define SSIZE_T_FMT \"%%zd\"\n");
73a46702 202#else
73a46702
PP
203if (sizeof(test_size_t) > sizeof (test_ulong_t))
204 fprintf(new, "#define SIZE_T_FMT \"%%llu\"\n");
74d8288d 205else if (sizeof(test_size_t) > sizeof (test_uint_t))
73a46702 206 fprintf(new, "#define SIZE_T_FMT \"%%lu\"\n");
74d8288d
JH
207else
208 fprintf(new, "#define SIZE_T_FMT \"%%u\"\n");
209
17c76198
PP
210if (sizeof(test_ssize_t) > sizeof(test_long_t))
211 fprintf(new, "#define SSIZE_T_FMT \"%%lld\"\n");
74d8288d 212else if (sizeof(test_ssize_t) > sizeof(test_int_t))
17c76198 213 fprintf(new, "#define SSIZE_T_FMT \"%%ld\"\n");
74d8288d
JH
214else
215 fprintf(new, "#define SSIZE_T_FMT \"%%d\"\n");
73a46702
PP
216#endif
217
b1c749bb 218/* Now search the makefile for certain settings */
059ec3d9
PH
219
220base = fopen("Makefile", "rb");
221if (base == NULL)
222 {
223 printf("*** Buildconfig: failed to open Makefile\n");
f1e894f3 224 (void)fclose(new);
059ec3d9
PH
225 exit(1);
226 }
227
228errno_quota[0] = 0; /* no over-riding value set */
229ostype[0] = 0; /* just in case */
230cc[0] = 0;
231
232while (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
319fprintf(new, "#define HAVE_IPV6 %s\n",
320 have_ipv6? "TRUE" : "FALSE");
321
322fprintf(new, "#define HAVE_ICONV %s\n",
323 have_iconv? "TRUE" : "FALSE");
324
325if (errno_quota[0] != 0)
326 fprintf(new, "\n#define ERRNO_QUOTA %s\n", errno_quota);
327
2548ba04
PH
328if (strcmp(cc, "gcc") == 0 &&
329 (strstr(ostype, "IRIX") != NULL || strstr(ostype, "AIX") != NULL))
059ec3d9
PH
330 {
331 fprintf(new, "\n/* This switch includes the code to fix the inet_ntoa() */");
2548ba04 332 fprintf(new, "\n/* bug when using gcc on an IRIX or AIX system. */");
059ec3d9
PH
333 fprintf(new, "\n#define USE_INET_NTOA_FIX");
334 }
335
336fprintf(new, "\n");
f1e894f3 337(void)fclose(base);
059ec3d9
PH
338
339
340/* Now handle the macros listed in the defaults */
341
342base = fopen("../src/config.h.defaults", "rb");
343if (base == NULL)
344 {
345 printf("*** Buildconfig: failed to open ../src/config.h.defaults\n");
f1e894f3 346 (void)fclose(new);
059ec3d9
PH
347 exit(1);
348 }
349
350while (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
97d17305
JH
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
059ec3d9
PH
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;
10385c15 409 int uid_not_set = 0;
059ec3d9
PH
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;
10385c15 464 uid_not_set = 1;
059ec3d9
PH
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
10385c15
PP
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) ||
655c5895
PP
563 ((username != NULL) && (
564 (strcmp(username, "root") == 0) ||
565 (strcmp(username, "toor") == 0) )))
10385c15
PP
566 {
567 printf("\n*** Exim's internal user must not be root.\n\n");
568 return 1;
569 }
570
059ec3d9
PH
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
35edf2ff
PH
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. */
059ec3d9 588
35edf2ff
PH
589 if (strcmp(name, "CONFIGURE_OWNER") == 0 ||
590 strcmp(name, "CONFIGURE_GROUP") == 0)
059ec3d9 591 {
8e669ac1 592 int isgroup = name[10] == 'G';
059ec3d9 593 uid_t uid = 0;
8e669ac1 594 gid_t gid = 0;
1ba28e2b
PP
595 const char *s;
596 const char *username = NULL;
597 const char *user = getenv(name);
059ec3d9
PH
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 {
35edf2ff 611 printf("\n*** %s contains the control character 0x%02X in "
059ec3d9 612 "one of the files\n in the \"Local\" directory. Please review "
35edf2ff 613 "your build-time\n configuration.\n\n", name, *s);
059ec3d9
PH
614 return 1;
615 }
616 }
617
618 /* Numeric uid given */
619
620 if (user[strspn(user, "0123456789")] == 0)
621 {
35edf2ff
PH
622 if (isgroup)
623 gid = (gid_t)atoi(user);
8e669ac1 624 else
35edf2ff 625 uid = (uid_t)atoi(user);
059ec3d9
PH
626 }
627
35edf2ff 628 /* Name given. Normally, we look up the uid or gid right away. However,
059ec3d9
PH
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 }
1ba28e2b 638else if (isgroup)
35edf2ff
PH
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
059ec3d9
PH
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 }
059ec3d9
PH
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)
35edf2ff
PH
668 {
669 if (isgroup)
670 fprintf(new, "#define CONFIGURE_GROUPNAME \"%s\"\n", username);
8e669ac1 671 else
35edf2ff
PH
672 fprintf(new, "#define CONFIGURE_OWNERNAME \"%s\"\n", username);
673 }
8e669ac1 674
35edf2ff
PH
675 if (isgroup)
676 fprintf(new, "#define CONFIGURE_GROUP %d\n", (int)gid);
8e669ac1 677 else
35edf2ff 678 fprintf(new, "#define CONFIGURE_OWNER %d\n", (int)uid);
059ec3d9
PH
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;
926e1192 695 int i, j;
059ec3d9
PH
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
926e1192 703 for (i = 1, j = 0; i <= count; list++, i++)
059ec3d9
PH
704 {
705 char name[64];
8e669ac1 706
059ec3d9
PH
707 p = list;
708 while (*list != 0 && *list != ':') list++;
709 strncpy(name, p, list-p);
710 name[list-p] = 0;
8e669ac1 711
926e1192
PH
712 if (name[0] == 0)
713 {
8e669ac1
PH
714 continue;
715 }
926e1192 716 else if (name[strspn(name, "0123456789")] == 0)
059ec3d9 717 {
926e1192 718 vector[j++] = (uid_t)atoi(name);
059ec3d9
PH
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 }
926e1192 730 vector[j++] = pw->pw_uid;
059ec3d9
PH
731 }
732 }
926e1192
PH
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");
059ec3d9
PH
736 }
737 continue;
738 }
739
6f1b3e5d
JH
740 /* WITH_CONTENT_SCAN is another special case: it must be set if it or
741 EXPERIMENTAL_DCC is set. */
c6e692d7
PH
742
743 if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
744 {
745 char *wcs = getenv("WITH_CONTENT_SCAN");
6a8f9482 746 char *dcc = getenv("EXPERIMENTAL_DCC");
03d5892b
JH
747 fprintf(new, wcs || dcc
748 ? "#define WITH_CONTENT_SCAN yes\n"
749 : "/* WITH_CONTENT_SCAN not set */\n");
c6e692d7 750 continue;
8e669ac1 751 }
c6e692d7 752
f444c2c7
JH
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
059ec3d9
PH
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 ||
7766a4f0 803 strcmp(value, "RADIUSCLIENTNEW") == 0 ||
059ec3d9
PH
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 }
ae20c809
JH
838 else
839 {
840 strncpy(buffer, ss, sizeof(buffer));
841 buffer[sizeof(buffer)-1] = 0;
842 }
059ec3d9
PH
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
a7cbbf50
PP
855 /* Timezone values HEADERS_CHARSET, TCP_WRAPPERS_DAEMON_NAME and
856 WHITELIST_D_MACROS get quoted */
059ec3d9
PH
857
858 else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
5dc43717 859 strcmp(name, "TCP_WRAPPERS_DAEMON_NAME") == 0||
a7cbbf50 860 strcmp(name, "HEADERS_CHARSET") == 0||
2c17bb02 861 strcmp(name, "WHITELIST_D_MACROS") == 0)
059ec3d9
PH
862 fprintf(new, "\"%s\"\n", value);
863
2c17bb02
PP
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 */
54c90be1
PP
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) ||
2c17bb02
PP
890 (strcmp(name, "EXIM_SERVER_DH_BITS_PRE2_12") == 0))
891 {
892 long nv;
893 char *end;
894 nv = strtol(value, &end, 10);
54c90be1 895 if (end != value && *end == '\0' && nv >= 512 && nv < 500000)
2c17bb02
PP
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
059ec3d9
PH
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
f1e894f3 947(void)fclose(base);
059ec3d9
PH
948
949/* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
950defined. */
951
952if (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
960fprintf(new, "\n/* End of config.h */\n");
f1e894f3 961(void)fclose(new);
059ec3d9
PH
962return 0;
963}
964
965/* End of buildconfig.c */