clean up group handling for sender & envelope addresses
[unix-history] / usr / src / usr.sbin / sendmail / src / readcf.c
CommitLineData
b2a81223 1/*
dc45ba8c 2 * Copyright (c) 1983 Eric P. Allman
24634489
KB
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
bee79b64 5 *
417f7a11 6 * %sccs.include.redist.c%
bee79b64 7 */
b2a81223
DF
8
9#ifndef lint
25792b6f 10static char sccsid[] = "@(#)readcf.c 8.81 (Berkeley) %G%";
bee79b64 11#endif /* not lint */
b2a81223 12
96faada8 13# include "sendmail.h"
6c87807d 14# include <grp.h>
efe7f723 15#if NAMED_BIND
ff87df81
EA
16# include <resolv.h>
17#endif
0ae1a7f9 18
0ae1a7f9
EA
19/*
20** READCF -- read control file.
21**
22** This routine reads the control file and builds the internal
23** form.
24**
2ae902c1
EA
25** The file is formatted as a sequence of lines, each taken
26** atomically. The first character of each line describes how
27** the line is to be interpreted. The lines are:
28** Dxval Define macro x to have value val.
29** Cxword Put word into class x.
30** Fxfile [fmt] Read file for lines to put into
31** class x. Use scanf string 'fmt'
32** or "%s" if not present. Fmt should
33** only produce one string-valued result.
34** Hname: value Define header with field-name 'name'
35** and value as specified; this will be
36** macro expanded immediately before
37** use.
38** Sn Use rewriting set n.
39** Rlhs rhs Rewrite addresses that match lhs to
40** be rhs.
2e3062fe
EA
41** Mn arg=val... Define mailer. n is the internal name.
42** Args specify mailer parameters.
a444c81b
EA
43** Oxvalue Set option x to value.
44** Pname=value Set precedence name to value.
fe3849ea
EA
45** Vversioncode[/vendorcode]
46** Version level/vendor name of
47** configuration syntax.
42fa5d67
EA
48** Kmapname mapclass arguments....
49** Define keyed lookup of a given class.
50** Arguments are class dependent.
2ae902c1 51**
0ae1a7f9
EA
52** Parameters:
53** cfname -- control file name.
66391bf0
EA
54** safe -- TRUE if this is the system config file;
55** FALSE otherwise.
a4076aed 56** e -- the main envelope.
0ae1a7f9
EA
57**
58** Returns:
59** none.
60**
61** Side Effects:
62** Builds several internal tables.
63*/
64
46f6ec52 65readcf(cfname)
0ae1a7f9 66 char *cfname;
66391bf0 67 bool safe;
a4076aed 68 register ENVELOPE *e;
0ae1a7f9
EA
69{
70 FILE *cf;
eaedbda3 71 int ruleset = 0;
8de3dfce 72 int nextruleset = MAXRWSETS;
eaedbda3 73 char *q;
611b763d 74 struct rewrite *rwp = NULL;
07b49560 75 char *bp;
fe3849ea 76 auto char *ep;
1627a785 77 int nfuzzy;
6c87807d
EA
78 char *file;
79 bool optional;
1be6e8d1 80 int mid;
0ae1a7f9
EA
81 char buf[MAXLINE];
82 register char *p;
0ae1a7f9 83 extern char **copyplist();
31709e9e 84 struct stat statb;
721fad23 85 char exbuf[MAXLINE];
148ea694 86 char pvpbuf[MAXLINE + MAXATOM];
314c8556 87 static char *null_list[1] = { NULL };
378e8da7 88 extern char *munchstring();
42fa5d67 89 extern void makemapentry();
0ae1a7f9 90
31709e9e
EA
91 FileName = cfname;
92 LineNumber = 0;
93
0ae1a7f9
EA
94 cf = fopen(cfname, "r");
95 if (cf == NULL)
96 {
31709e9e 97 syserr("cannot open");
0ae1a7f9
EA
98 exit(EX_OSFILE);
99 }
100
31709e9e
EA
101 if (fstat(fileno(cf), &statb) < 0)
102 {
103 syserr("cannot fstat");
104 exit(EX_OSFILE);
105 }
106
107 if (!S_ISREG(statb.st_mode))
108 {
109 syserr("not a plain file");
110 exit(EX_OSFILE);
111 }
112
113 if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
114 {
a90a7c55
EA
115 if (OpMode == MD_DAEMON || OpMode == MD_FREEZE)
116 fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
117 FileName);
118#ifdef LOG
119 if (LogLevel > 0)
120 syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions",
121 FileName);
122#endif
31709e9e
EA
123 }
124
46500bf5
EA
125#ifdef XLA
126 xla_zero();
127#endif
128
07b49560 129 while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
0ae1a7f9 130 {
07b49560
EA
131 if (bp[0] == '#')
132 {
133 if (bp != buf)
134 free(bp);
72f91c2e 135 continue;
07b49560 136 }
72f91c2e 137
1be6e8d1 138 /* do macro expansion mappings */
07b49560 139 for (p = bp; *p != '\0'; p++)
a73ae8ac 140 {
07b49560 141 if (*p == '#' && p > bp && ConfigLevel >= 3)
31709e9e
EA
142 {
143 /* this is an on-line comment */
144 register char *e;
145
2bee003d 146 switch (*--p & 0377)
31709e9e 147 {
2bee003d 148 case MACROEXPAND:
31709e9e
EA
149 /* it's from $# -- let it go through */
150 p++;
151 break;
152
153 case '\\':
154 /* it's backslash escaped */
155 (void) strcpy(p, p + 1);
156 break;
157
158 default:
159 /* delete preceeding white space */
2bee003d 160 while (isascii(*p) && isspace(*p) && p > bp)
31709e9e 161 p--;
f3d8f6d6 162 if ((e = strchr(++p, '\n')) != NULL)
31709e9e
EA
163 (void) strcpy(p, e);
164 else
165 p[0] = p[1] = '\0';
166 break;
167 }
168 continue;
169 }
170
1be6e8d1 171 if (*p != '$' || p[1] == '\0')
a73ae8ac
EA
172 continue;
173
174 if (p[1] == '$')
175 {
176 /* actual dollar sign.... */
7eff3306 177 (void) strcpy(p, p + 1);
a73ae8ac
EA
178 continue;
179 }
180
181 /* convert to macro expansion character */
1be6e8d1
EA
182 *p++ = MACROEXPAND;
183
184 /* convert macro name to code */
185 *p = macid(p, &ep);
186 if (ep != p)
187 strcpy(p + 1, ep);
a73ae8ac
EA
188 }
189
190 /* interpret this line */
fe3849ea 191 errno = 0;
07b49560 192 switch (bp[0])
0ae1a7f9 193 {
0ae1a7f9 194 case '\0':
0ae1a7f9
EA
195 case '#': /* comment */
196 break;
197
198 case 'R': /* rewriting rule */
07b49560 199 for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
0ae1a7f9
EA
200 continue;
201
202 if (*p == '\0')
721fad23 203 {
8561eb96 204 syserr("invalid rewrite line \"%s\" (tab expected)", bp);
721fad23
EA
205 break;
206 }
207
208 /* allocate space for the rule header */
209 if (rwp == NULL)
210 {
211 RewriteRules[ruleset] = rwp =
212 (struct rewrite *) xalloc(sizeof *rwp);
213 }
0ae1a7f9
EA
214 else
215 {
721fad23
EA
216 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
217 rwp = rwp->r_next;
0ae1a7f9 218 }
721fad23
EA
219 rwp->r_next = NULL;
220
221 /* expand and save the LHS */
222 *p = '\0';
832e8a27 223 expand(&bp[1], exbuf, sizeof exbuf, e);
148ea694 224 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
800c836f 225 sizeof pvpbuf, NULL, NULL);
1627a785 226 nfuzzy = 0;
721fad23 227 if (rwp->r_lhs != NULL)
1627a785
EA
228 {
229 register char **ap;
230
721fad23 231 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
1627a785
EA
232
233 /* count the number of fuzzy matches in LHS */
234 for (ap = rwp->r_lhs; *ap != NULL; ap++)
235 {
2f7be259
EA
236 char *botch;
237
238 botch = NULL;
2bee003d 239 switch (**ap & 0377)
1627a785
EA
240 {
241 case MATCHZANY:
242 case MATCHANY:
243 case MATCHONE:
244 case MATCHCLASS:
245 case MATCHNCLASS:
246 nfuzzy++;
2f7be259
EA
247 break;
248
249 case MATCHREPL:
250 botch = "$0-$9";
251 break;
252
d30b0654 253#if 0
2f7be259
EA
254 case CANONNET:
255 botch = "$#";
256 break;
257
2f7be259
EA
258 case CANONUSER:
259 botch = "$:";
260 break;
d30b0654 261#endif /* 0 */
2f7be259
EA
262
263 case CALLSUBR:
264 botch = "$>";
265 break;
266
267 case CONDIF:
268 botch = "$?";
269 break;
270
271 case CONDELSE:
272 botch = "$|";
273 break;
274
275 case CONDFI:
276 botch = "$.";
277 break;
278
279 case HOSTBEGIN:
280 botch = "$[";
281 break;
282
283 case HOSTEND:
284 botch = "$]";
285 break;
286
287 case LOOKUPBEGIN:
288 botch = "$(";
289 break;
290
291 case LOOKUPEND:
292 botch = "$)";
293 break;
1627a785 294 }
2f7be259
EA
295 if (botch != NULL)
296 syserr("Inappropriate use of %s on LHS",
297 botch);
1627a785
EA
298 }
299 }
f62b79ae 300 else
314c8556 301 {
f62b79ae 302 syserr("R line: null LHS");
314c8556
EA
303 rwp->r_lhs = null_list;
304 }
721fad23
EA
305
306 /* expand and save the RHS */
307 while (*++p == '\t')
308 continue;
b6d9b77f
EA
309 q = p;
310 while (*p != '\0' && *p != '\t')
311 p++;
312 *p = '\0';
832e8a27 313 expand(q, exbuf, sizeof exbuf, e);
148ea694 314 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
800c836f 315 sizeof pvpbuf, NULL, NULL);
721fad23 316 if (rwp->r_rhs != NULL)
1627a785
EA
317 {
318 register char **ap;
319
721fad23 320 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
1627a785
EA
321
322 /* check no out-of-bounds replacements */
323 nfuzzy += '0';
324 for (ap = rwp->r_rhs; *ap != NULL; ap++)
325 {
2f7be259
EA
326 char *botch;
327
328 botch = NULL;
329 switch (**ap & 0377)
1627a785 330 {
2f7be259
EA
331 case MATCHREPL:
332 if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
333 {
334 syserr("replacement $%c out of bounds",
335 (*ap)[1]);
336 }
337 break;
338
339 case MATCHZANY:
340 botch = "$*";
341 break;
342
343 case MATCHANY:
344 botch = "$+";
345 break;
346
347 case MATCHONE:
348 botch = "$-";
349 break;
350
351 case MATCHCLASS:
352 botch = "$=";
353 break;
354
355 case MATCHNCLASS:
356 botch = "$~";
357 break;
1627a785 358 }
2f7be259
EA
359 if (botch != NULL)
360 syserr("Inappropriate use of %s on RHS",
361 botch);
1627a785
EA
362 }
363 }
f62b79ae 364 else
314c8556 365 {
f62b79ae 366 syserr("R line: null RHS");
314c8556
EA
367 rwp->r_rhs = null_list;
368 }
0ae1a7f9
EA
369 break;
370
f65e7ded 371 case 'S': /* select rewriting set */
bbf6e157
EA
372 for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
373 continue;
8de3dfce 374 if (!isascii(*p))
bbf6e157
EA
375 {
376 syserr("invalid argument to S line: \"%.20s\"",
377 &bp[1]);
378 break;
379 }
8de3dfce 380 if (isdigit(*p))
edfd5d70 381 {
8de3dfce
EA
382 ruleset = atoi(p);
383 if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
384 {
385 syserr("bad ruleset %d (%d max)",
386 ruleset, MAXRWSETS / 2);
387 ruleset = 0;
388 }
389 }
390 else
391 {
392 STAB *s;
393 char delim;
394
395 q = p;
396 while (*p != '\0' && isascii(*p) &&
397 (isalnum(*p) || strchr("-_$", *p) != NULL))
398 p++;
399 while (isascii(*p) && isspace(*p))
400 *p++ = '\0';
401 delim = *p;
402 if (delim != '\0')
403 *p++ = '\0';
404 s = stab(q, ST_RULESET, ST_ENTER);
405 if (s->s_ruleset != 0)
406 ruleset = s->s_ruleset;
407 else if (delim == '=')
408 {
409 ruleset = atoi(p);
410 if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
411 {
412 syserr("bad ruleset %s = %d (%d max)",
413 q, ruleset, MAXRWSETS / 2);
414 ruleset = 0;
415 }
416 }
417 else if ((ruleset = --nextruleset) < MAXRWSETS / 2)
418 {
419 syserr("%s: too many named rulesets (%d max)",
420 q, MAXRWSETS / 2);
421 ruleset = 0;
422 }
423 s->s_ruleset = ruleset;
edfd5d70 424 }
f65e7ded
EA
425 rwp = NULL;
426 break;
427
0ae1a7f9 428 case 'D': /* macro definition */
1be6e8d1
EA
429 mid = macid(&bp[1], &ep);
430 p = munchstring(ep, NULL);
431 define(mid, newstr(p), e);
0ae1a7f9
EA
432 break;
433
2f0c5bd8 434 case 'H': /* required header line */
9905202c 435 (void) chompheader(&bp[1], TRUE, NULL, e);
2f0c5bd8
EA
436 break;
437
13834bfc 438 case 'C': /* word class */
de70d842
EA
439 case 'T': /* trusted user (set class `t') */
440 if (bp[0] == 'C')
441 {
442 mid = macid(&bp[1], &ep);
832e8a27 443 expand(ep, exbuf, sizeof exbuf, e);
de70d842
EA
444 p = exbuf;
445 }
446 else
447 {
448 mid = 't';
449 p = &bp[1];
450 }
451 while (*p != '\0')
13834bfc
EA
452 {
453 register char *wd;
454 char delim;
13834bfc 455
2bee003d 456 while (*p != '\0' && isascii(*p) && isspace(*p))
13834bfc
EA
457 p++;
458 wd = p;
2bee003d 459 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
13834bfc
EA
460 p++;
461 delim = *p;
462 *p = '\0';
463 if (wd[0] != '\0')
1be6e8d1 464 setclass(mid, wd);
13834bfc
EA
465 *p = delim;
466 }
467 break;
468
d15c899b 469 case 'F': /* word class from file */
1be6e8d1
EA
470 mid = macid(&bp[1], &ep);
471 for (p = ep; isascii(*p) && isspace(*p); )
6c87807d
EA
472 p++;
473 if (p[0] == '-' && p[1] == 'o')
474 {
475 optional = TRUE;
476 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
477 p++;
478 while (isascii(*p) && isspace(*p))
c9f8d78e 479 p++;
6c87807d
EA
480 }
481 else
482 optional = FALSE;
483 file = p;
484 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
485 p++;
d15c899b
EA
486 if (*p == '\0')
487 p = "%s";
488 else
489 {
490 *p = '\0';
491 while (isascii(*++p) && isspace(*p))
492 continue;
493 }
6c87807d 494 fileclass(bp[1], file, p, safe, optional);
d15c899b
EA
495 break;
496
b4f81c5d
EA
497#ifdef XLA
498 case 'L': /* extended load average description */
499 xla_init(&bp[1]);
500 break;
501#endif
502
9c6d4c70 503 case 'M': /* define mailer */
46f6ec52 504 makemailer(&buf[1]);
9c6d4c70
EA
505 break;
506
a444c81b 507 case 'O': /* set option */
46f6ec52 508 setoption(buf[1], &buf[2], FALSE);
a444c81b
EA
509 break;
510
511 case 'P': /* set precedence */
512 if (NumPriorities >= MAXPRIORITIES)
513 {
eaedbda3 514 toomany('P', MAXPRIORITIES);
a444c81b
EA
515 break;
516 }
07b49560 517 for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
a444c81b
EA
518 continue;
519 if (*p == '\0')
520 goto badline;
521 *p = '\0';
07b49560 522 Priorities[NumPriorities].pri_name = newstr(&bp[1]);
a444c81b
EA
523 Priorities[NumPriorities].pri_val = atoi(++p);
524 NumPriorities++;
525 break;
526
f76f5861 527 case 'V': /* configuration syntax version */
bbf6e157
EA
528 for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
529 continue;
530 if (!isascii(*p) || !isdigit(*p))
531 {
532 syserr("invalid argument to V line: \"%.20s\"",
533 &bp[1]);
534 break;
535 }
fe3849ea 536 ConfigLevel = strtol(p, &ep, 10);
199d44c8
EA
537 if (ConfigLevel >= 5)
538 {
539 /* level 5 configs have short name in $w */
540 p = macvalue('w', e);
541 if (p != NULL && (p = strchr(p, '.')) != NULL)
542 *p = '\0';
543 }
fe3849ea
EA
544 if (*ep++ == '/')
545 {
546 /* extract vendor code */
547 for (p = ep; isascii(*p) && isalpha(*p); )
548 p++;
549 *p = '\0';
550
551 if (!setvendor(ep))
552 syserr("invalid V line vendor code: \"%s\"",
553 ep);
554 }
f76f5861
EA
555 break;
556
42fa5d67 557 case 'K':
07b49560 558 makemapentry(&bp[1]);
42fa5d67
EA
559 break;
560
0ae1a7f9 561 default:
13834bfc 562 badline:
07b49560 563 syserr("unknown control line \"%s\"", bp);
0ae1a7f9 564 }
07b49560
EA
565 if (bp != buf)
566 free(bp);
0ae1a7f9 567 }
72f91c2e
EA
568 if (ferror(cf))
569 {
31709e9e 570 syserr("I/O read error", cfname);
72f91c2e
EA
571 exit(EX_OSFILE);
572 }
573 fclose(cf);
7338e3d4 574 FileName = NULL;
32fd13db 575
418a3328
EA
576 /* initialize host maps from local service tables */
577 inithostmaps();
82625f68
EA
578
579 /* determine if we need to do special name-server frotz */
580 {
581 int nmaps;
582 char *maptype[MAXMAPSTACK];
583 short mapreturn[MAXMAPACTIONS];
584
585 nmaps = switch_map_find("hosts", maptype, mapreturn);
586 UseNameServer = FALSE;
587 if (nmaps > 0 && nmaps <= MAXMAPSTACK)
588 {
589 register int mapno;
590
591 for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++)
592 {
593 if (strcmp(maptype[mapno], "dns") == 0)
594 UseNameServer = TRUE;
595 }
596 }
7830e89b
EA
597
598#ifdef HESIOD
599 nmaps = switch_map_find("passwd", maptype, mapreturn);
600 UseHesiod = FALSE;
601 if (nmaps > 0 && nmaps <= MAXMAPSTACK)
602 {
603 register int mapno;
604
605 for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++)
606 {
607 if (strcmp(maptype[mapno], "hesiod") == 0)
608 UseHesiod = TRUE;
609 }
610 }
611#endif
82625f68 612 }
9c6d4c70
EA
613}
614\f/*
eaedbda3
EA
615** TOOMANY -- signal too many of some option
616**
617** Parameters:
618** id -- the id of the error line
619** maxcnt -- the maximum possible values
620**
621** Returns:
622** none.
623**
624** Side Effects:
625** gives a syserr.
626*/
627
628toomany(id, maxcnt)
629 char id;
630 int maxcnt;
631{
7338e3d4 632 syserr("too many %c lines, %d max", id, maxcnt);
eaedbda3
EA
633}
634\f/*
2ae902c1
EA
635** FILECLASS -- read members of a class from a file
636**
637** Parameters:
638** class -- class to define.
639** filename -- name of file to read.
640** fmt -- scanf string to use for match.
6c87807d
EA
641** safe -- if set, this is a safe read.
642** optional -- if set, it is not an error for the file to
643** not exist.
2ae902c1
EA
644**
645** Returns:
646** none
647**
648** Side Effects:
649**
650** puts all lines in filename that match a scanf into
651** the named class.
652*/
653
6c87807d 654fileclass(class, filename, fmt, safe, optional)
2ae902c1
EA
655 int class;
656 char *filename;
657 char *fmt;
66391bf0 658 bool safe;
6c87807d 659 bool optional;
2ae902c1 660{
c82629c0 661 FILE *f;
51cc57b9 662 int sff;
2ae902c1
EA
663 char buf[MAXLINE];
664
5a1c6c22
EA
665 if (tTd(37, 2))
666 printf("fileclass(%s, fmt=%s)\n", filename, fmt);
667
c0f36a4e
EA
668 if (filename[0] == '|')
669 {
670 syserr("fileclass: pipes (F%c%s) not supported due to security problems",
671 class, filename);
672 return;
673 }
51cc57b9
EA
674 sff = SFF_REGONLY;
675 if (safe)
676 sff |= SFF_OPENASROOT;
677 f = safefopen(filename, O_RDONLY, 0, sff);
c2cce1ca 678 if (f == NULL)
2ae902c1 679 {
c2cce1ca
EA
680 if (!optional)
681 syserr("fileclass: cannot open %s", filename);
2ae902c1
EA
682 return;
683 }
684
685 while (fgets(buf, sizeof buf, f) != NULL)
686 {
687 register STAB *s;
c82629c0
EA
688 register char *p;
689# ifdef SCANF
2ae902c1
EA
690 char wordbuf[MAXNAME+1];
691
692 if (sscanf(buf, fmt, wordbuf) != 1)
693 continue;
c82629c0 694 p = wordbuf;
f3d8f6d6 695# else /* SCANF */
c82629c0 696 p = buf;
f3d8f6d6 697# endif /* SCANF */
c82629c0
EA
698
699 /*
700 ** Break up the match into words.
701 */
702
703 while (*p != '\0')
704 {
705 register char *q;
706
707 /* strip leading spaces */
2bee003d 708 while (isascii(*p) && isspace(*p))
c82629c0
EA
709 p++;
710 if (*p == '\0')
711 break;
712
713 /* find the end of the word */
714 q = p;
2bee003d 715 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
c82629c0
EA
716 p++;
717 if (*p != '\0')
718 *p++ = '\0';
719
720 /* enter the word in the symbol table */
5a1c6c22 721 setclass(class, q);
c82629c0 722 }
2ae902c1
EA
723 }
724
66391bf0 725 (void) fclose(f);
2ae902c1
EA
726}
727\f/*
9c6d4c70
EA
728** MAKEMAILER -- define a new mailer.
729**
730** Parameters:
e9b10d8d
EA
731** line -- description of mailer. This is in labeled
732** fields. The fields are:
e9b10d8d 733** A -- the argv for this mailer
a542cc51
EA
734** C -- the character set for MIME conversions
735** D -- the directory to run in
e9b10d8d 736** E -- the eol string
a542cc51
EA
737** F -- the flags associated with the mailer
738** L -- the maximum line length
739** M -- the maximum message size
740** P -- the path to the mailer
741** R -- the recipient rewriting set
742** S -- the sender rewriting set
743** T -- the mailer type (for DSNs)
744** U -- the uid to run as
e9b10d8d 745** The first word is the canonical name of the mailer.
9c6d4c70
EA
746**
747** Returns:
748** none.
749**
750** Side Effects:
751** enters the mailer into the mailer table.
752*/
753
46f6ec52 754makemailer(line)
9c6d4c70
EA
755 char *line;
756{
757 register char *p;
d64deb33
EA
758 register struct mailer *m;
759 register STAB *s;
760 int i;
e9b10d8d 761 char fcode;
68f7099c 762 auto char *endp;
9c6d4c70 763 extern int NextMailer;
e9b10d8d
EA
764 extern char **makeargv();
765 extern char *munchstring();
97ad25b6 766 extern long atol();
9c6d4c70 767
e9b10d8d
EA
768 /* allocate a mailer and set up defaults */
769 m = (struct mailer *) xalloc(sizeof *m);
770 bzero((char *) m, sizeof *m);
e9b10d8d 771 m->m_eol = "\n";
1ff27f9b 772 m->m_uid = m->m_gid = 0;
e9b10d8d
EA
773
774 /* collect the mailer name */
2bee003d 775 for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
e9b10d8d
EA
776 continue;
777 if (*p != '\0')
778 *p++ = '\0';
779 m->m_name = newstr(line);
780
781 /* now scan through and assign info from the fields */
782 while (*p != '\0')
9c6d4c70 783 {
9e2cf26f
EA
784 auto char *delimptr;
785
2bee003d 786 while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
e9b10d8d
EA
787 p++;
788
789 /* p now points to field code */
790 fcode = *p;
791 while (*p != '\0' && *p != '=' && *p != ',')
792 p++;
793 if (*p++ != '=')
794 {
72f91c2e 795 syserr("mailer %s: `=' expected", m->m_name);
e9b10d8d
EA
796 return;
797 }
2bee003d 798 while (isascii(*p) && isspace(*p))
e9b10d8d
EA
799 p++;
800
801 /* p now points to the field body */
9e2cf26f 802 p = munchstring(p, &delimptr);
e9b10d8d
EA
803
804 /* install the field into the mailer struct */
805 switch (fcode)
806 {
807 case 'P': /* pathname */
808 m->m_mailer = newstr(p);
809 break;
810
811 case 'F': /* flags */
1dbda134 812 for (; *p != '\0'; p++)
2bee003d 813 if (!(isascii(*p) && isspace(*p)))
72f91c2e 814 setbitn(*p, m->m_flags);
e9b10d8d
EA
815 break;
816
817 case 'S': /* sender rewriting ruleset */
818 case 'R': /* recipient rewriting ruleset */
68f7099c 819 i = strtol(p, &endp, 10);
e9b10d8d
EA
820 if (i < 0 || i >= MAXRWSETS)
821 {
822 syserr("invalid rewrite set, %d max", MAXRWSETS);
823 return;
824 }
825 if (fcode == 'S')
68f7099c 826 m->m_sh_rwset = m->m_se_rwset = i;
e9b10d8d 827 else
68f7099c
EA
828 m->m_rh_rwset = m->m_re_rwset = i;
829
830 p = endp;
98d6de2d 831 if (*p++ == '/')
68f7099c
EA
832 {
833 i = strtol(p, NULL, 10);
834 if (i < 0 || i >= MAXRWSETS)
835 {
836 syserr("invalid rewrite set, %d max",
837 MAXRWSETS);
838 return;
839 }
840 if (fcode == 'S')
841 m->m_sh_rwset = i;
842 else
843 m->m_rh_rwset = i;
844 }
e9b10d8d
EA
845 break;
846
847 case 'E': /* end of line string */
848 m->m_eol = newstr(p);
849 break;
850
851 case 'A': /* argument vector */
852 m->m_argv = makeargv(p);
853 break;
97ad25b6
EA
854
855 case 'M': /* maximum message size */
856 m->m_maxsize = atol(p);
857 break;
8657d05f
EA
858
859 case 'L': /* maximum line length */
860 m->m_linelimit = atoi(p);
861 break;
6f5db107
EA
862
863 case 'D': /* working directory */
864 m->m_execdir = newstr(p);
865 break;
1ff27f9b 866
3caf3b1f
EA
867 case 'C': /* default charset */
868 m->m_defcharset = newstr(p);
869 break;
870
51d448e5
EA
871 case 'T': /* MTA Type */
872 m->m_mtatype = newstr(p);
873 p = strchr(m->m_mtatype, '/');
874 if (p != NULL)
875 {
876 *p++ = '\0';
877 if (*p == '\0')
878 p = NULL;
879 }
880 if (p == NULL)
881 m->m_addrtype = m->m_mtatype;
882 else
883 {
884 m->m_addrtype = p;
885 p = strchr(p, '/');
886 }
887 if (p != NULL)
888 {
889 *p++ = '\0';
890 if (*p == '\0')
891 p = NULL;
892 }
893 if (p == NULL)
894 m->m_diagtype = m->m_mtatype;
895 else
896 m->m_diagtype = p;
d51d925d
EA
897 break;
898
1ff27f9b
EA
899 case 'U': /* user id */
900 if (isascii(*p) && !isdigit(*p))
901 {
902 char *q = p;
903 struct passwd *pw;
904
905 while (isascii(*p) && isalnum(*p))
906 p++;
907 while (isascii(*p) && isspace(*p))
908 *p++ = '\0';
909 if (*p != '\0')
910 *p++ = '\0';
5b7a2dfe 911 pw = sm_getpwnam(q);
1ff27f9b
EA
912 if (pw == NULL)
913 syserr("readcf: mailer U= flag: unknown user %s", q);
914 else
915 {
916 m->m_uid = pw->pw_uid;
917 m->m_gid = pw->pw_gid;
918 }
919 }
920 else
921 {
922 auto char *q;
923
924 m->m_uid = strtol(p, &q, 0);
925 p = q;
926 }
927 while (isascii(*p) && isspace(*p))
928 p++;
929 if (*p == '\0')
930 break;
931 if (isascii(*p) && !isdigit(*p))
932 {
933 char *q = p;
934 struct group *gr;
935
936 while (isascii(*p) && isalnum(*p))
937 p++;
938 *p++ = '\0';
939 gr = getgrnam(q);
940 if (gr == NULL)
941 syserr("readcf: mailer U= flag: unknown group %s", q);
942 else
943 m->m_gid = gr->gr_gid;
944 }
945 else
946 {
947 m->m_gid = strtol(p, NULL, 0);
948 }
1ff27f9b 949 break;
e9b10d8d
EA
950 }
951
9e2cf26f 952 p = delimptr;
9c6d4c70
EA
953 }
954
6ae0f7c6
EA
955 /* do some rationality checking */
956 if (m->m_argv == NULL)
957 {
958 syserr("M%s: A= argument required", m->m_name);
959 return;
960 }
961 if (m->m_mailer == NULL)
962 {
963 syserr("M%s: P= argument required", m->m_name);
964 return;
965 }
966
e9b10d8d 967 if (NextMailer >= MAXMAILERS)
9c6d4c70 968 {
e9b10d8d 969 syserr("too many mailers defined (%d max)", MAXMAILERS);
9c6d4c70
EA
970 return;
971 }
98e5062b 972
a542cc51
EA
973 /* do some heuristic cleanup for back compatibility */
974 if (bitnset(M_LIMITS, m->m_flags))
975 {
976 if (m->m_linelimit == 0)
977 m->m_linelimit = SMTPLINELIM;
978 if (ConfigLevel < 2)
979 setbitn(M_7BITS, m->m_flags);
980 }
981
51d448e5 982 if (ConfigLevel < 6 &&
a542cc51 983 (strcmp(m->m_mailer, "[IPC]") == 0 ||
dc1b43b5 984 strcmp(m->m_mailer, "[TCP]") == 0))
51d448e5
EA
985 {
986 if (m->m_mtatype == NULL)
987 m->m_mtatype = "dns";
988 if (m->m_addrtype == NULL)
989 m->m_addrtype = "rfc822";
990 if (m->m_diagtype == NULL)
991 m->m_diagtype = "smtp";
992 }
a542cc51
EA
993
994 /* enter the mailer into the symbol table */
e9b10d8d 995 s = stab(m->m_name, ST_MAILER, ST_ENTER);
98e5062b
EA
996 if (s->s_mailer != NULL)
997 {
998 i = s->s_mailer->m_mno;
999 free(s->s_mailer);
1000 }
1001 else
1002 {
1003 i = NextMailer++;
1004 }
1005 Mailer[i] = s->s_mailer = m;
7e70d3c8 1006 m->m_mno = i;
e9b10d8d
EA
1007}
1008\f/*
1009** MUNCHSTRING -- translate a string into internal form.
1010**
1011** Parameters:
1012** p -- the string to munch.
9e2cf26f
EA
1013** delimptr -- if non-NULL, set to the pointer of the
1014** field delimiter character.
e9b10d8d
EA
1015**
1016** Returns:
1017** the munched string.
e9b10d8d
EA
1018*/
1019
1020char *
9e2cf26f 1021munchstring(p, delimptr)
e9b10d8d 1022 register char *p;
9e2cf26f 1023 char **delimptr;
e9b10d8d
EA
1024{
1025 register char *q;
1026 bool backslash = FALSE;
1027 bool quotemode = FALSE;
1028 static char buf[MAXLINE];
e9b10d8d
EA
1029
1030 for (q = buf; *p != '\0'; p++)
d64deb33 1031 {
e9b10d8d
EA
1032 if (backslash)
1033 {
1034 /* everything is roughly literal */
f79a1e64 1035 backslash = FALSE;
e9b10d8d
EA
1036 switch (*p)
1037 {
1038 case 'r': /* carriage return */
1039 *q++ = '\r';
1040 continue;
1041
1042 case 'n': /* newline */
1043 *q++ = '\n';
1044 continue;
1045
1046 case 'f': /* form feed */
1047 *q++ = '\f';
1048 continue;
1049
1050 case 'b': /* backspace */
1051 *q++ = '\b';
1052 continue;
1053 }
1054 *q++ = *p;
e9b10d8d
EA
1055 }
1056 else
1057 {
1058 if (*p == '\\')
1059 backslash = TRUE;
1060 else if (*p == '"')
1061 quotemode = !quotemode;
1062 else if (quotemode || *p != ',')
1063 *q++ = *p;
1064 else
1065 break;
1066 }
d64deb33 1067 }
9c6d4c70 1068
9e2cf26f
EA
1069 if (delimptr != NULL)
1070 *delimptr = p;
e9b10d8d
EA
1071 *q++ = '\0';
1072 return (buf);
1073}
1074\f/*
1075** MAKEARGV -- break up a string into words
1076**
1077** Parameters:
1078** p -- the string to break up.
1079**
1080** Returns:
1081** a char **argv (dynamically allocated)
1082**
1083** Side Effects:
1084** munges p.
1085*/
1086
1087char **
1088makeargv(p)
1089 register char *p;
1090{
1091 char *q;
1092 int i;
1093 char **avp;
1094 char *argv[MAXPV + 1];
0ae1a7f9 1095
e9b10d8d
EA
1096 /* take apart the words */
1097 i = 0;
1098 while (*p != '\0' && i < MAXPV)
9c6d4c70 1099 {
e9b10d8d 1100 q = p;
2bee003d 1101 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
e9b10d8d 1102 p++;
2bee003d 1103 while (isascii(*p) && isspace(*p))
e9b10d8d
EA
1104 *p++ = '\0';
1105 argv[i++] = newstr(q);
9c6d4c70 1106 }
e9b10d8d 1107 argv[i++] = NULL;
9c6d4c70 1108
e9b10d8d
EA
1109 /* now make a copy of the argv */
1110 avp = (char **) xalloc(sizeof *avp * i);
0920c169 1111 bcopy((char *) argv, (char *) avp, sizeof *avp * i);
e9b10d8d
EA
1112
1113 return (avp);
0ae1a7f9
EA
1114}
1115\f/*
1116** PRINTRULES -- print rewrite rules (for debugging)
1117**
1118** Parameters:
1119** none.
1120**
1121** Returns:
1122** none.
1123**
1124** Side Effects:
1125** prints rewrite rules.
1126*/
1127
1128printrules()
1129{
1130 register struct rewrite *rwp;
f65e7ded 1131 register int ruleset;
0ae1a7f9 1132
f65e7ded 1133 for (ruleset = 0; ruleset < 10; ruleset++)
0ae1a7f9 1134 {
f65e7ded
EA
1135 if (RewriteRules[ruleset] == NULL)
1136 continue;
d64deb33 1137 printf("\n----Rule Set %d:", ruleset);
0ae1a7f9 1138
f65e7ded 1139 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
0ae1a7f9 1140 {
d64deb33
EA
1141 printf("\nLHS:");
1142 printav(rwp->r_lhs);
1143 printf("RHS:");
1144 printav(rwp->r_rhs);
0ae1a7f9 1145 }
0ae1a7f9
EA
1146 }
1147}
bdd1eb9a
EA
1148\f/*
1149** PRINTMAILER -- print mailer structure (for debugging)
1150**
1151** Parameters:
1152** m -- the mailer to print
1153**
1154** Returns:
1155** none.
1156*/
74c5fe7c 1157
bdd1eb9a
EA
1158printmailer(m)
1159 register MAILER *m;
1160{
1161 int j;
1162
1163 printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=",
1164 m->m_mno, m->m_name,
1165 m->m_mailer, m->m_se_rwset, m->m_sh_rwset,
1166 m->m_re_rwset, m->m_rh_rwset, m->m_maxsize,
1167 m->m_uid, m->m_gid);
1168 for (j = '\0'; j <= '\177'; j++)
1169 if (bitnset(j, m->m_flags))
1170 (void) putchar(j);
1171 printf(" L=%d E=", m->m_linelimit);
1172 xputs(m->m_eol);
1173 if (m->m_defcharset != NULL)
1174 printf(" C=%s", m->m_defcharset);
51d448e5
EA
1175 printf(" T=%s/%s/%s",
1176 m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype,
1177 m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype,
1178 m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype);
bdd1eb9a
EA
1179 if (m->m_argv != NULL)
1180 {
1181 char **a = m->m_argv;
1182
1183 printf(" A=");
1184 while (*a != NULL)
1185 {
1186 if (a != m->m_argv)
1187 printf(" ");
1188 xputs(*a++);
1189 }
1190 }
1191 printf("\n");
1192}
9c6d4c70 1193\f/*
a691a4a6
EA
1194** SETOPTION -- set global processing option
1195**
1196** Parameters:
1197** opt -- option name.
1198** val -- option value (as a text string).
c1e24818
EA
1199** sticky -- if set, don't let other setoptions override
1200** this value.
8c8e8e94 1201** e -- the main envelope.
a691a4a6
EA
1202**
1203** Returns:
1204** none.
1205**
1206** Side Effects:
1207** Sets options as implied by the arguments.
1208*/
1209
1dbda134 1210static BITMAP StickyOpt; /* set if option is stuck */
c1e24818 1211
ff87df81 1212
efe7f723 1213#if NAMED_BIND
ff87df81
EA
1214
1215struct resolverflags
1216{
1217 char *rf_name; /* name of the flag */
1218 long rf_bits; /* bits to set/clear */
1219} ResolverFlags[] =
1220{
1221 "debug", RES_DEBUG,
1222 "aaonly", RES_AAONLY,
1223 "usevc", RES_USEVC,
1224 "primary", RES_PRIMARY,
1225 "igntc", RES_IGNTC,
1226 "recurse", RES_RECURSE,
1227 "defnames", RES_DEFNAMES,
1228 "stayopen", RES_STAYOPEN,
1229 "dnsrch", RES_DNSRCH,
4c499543 1230 "true", 0, /* to avoid error on old syntax */
ff87df81
EA
1231 NULL, 0
1232};
1233
1234#endif
1235
2a58b3a7
EA
1236struct optioninfo
1237{
1238 char *o_name; /* long name of option */
fddf2552 1239 u_char o_code; /* short name of option */
2a58b3a7
EA
1240 bool o_safe; /* safe for random people to use */
1241} OptionTab[] =
1242{
6d04ef05
EA
1243 "SevenBitInput", '7', TRUE,
1244 "EightBitMode", '8', TRUE,
1245 "AliasFile", 'A', FALSE,
1246 "AliasWait", 'a', FALSE,
1247 "BlankSub", 'B', FALSE,
1248 "MinFreeBlocks", 'b', TRUE,
1249 "CheckpointInterval", 'C', TRUE,
1250 "HoldExpensive", 'c', FALSE,
1251 "AutoRebuildAliases", 'D', FALSE,
1252 "DeliveryMode", 'd', TRUE,
1253 "ErrorHeader", 'E', FALSE,
1254 "ErrorMode", 'e', TRUE,
1255 "TempFileMode", 'F', FALSE,
1256 "SaveFromLine", 'f', FALSE,
1257 "MatchGECOS", 'G', FALSE,
1258 "HelpFile", 'H', FALSE,
1259 "MaxHopCount", 'h', FALSE,
d84bd6b5 1260 "ResolverOptions", 'I', FALSE,
6d04ef05
EA
1261 "IgnoreDots", 'i', TRUE,
1262 "ForwardPath", 'J', FALSE,
1263 "SendMimeErrors", 'j', TRUE,
1264 "ConnectionCacheSize", 'k', FALSE,
1265 "ConnectionCacheTimeout", 'K', FALSE,
1266 "UseErrorsTo", 'l', FALSE,
1267 "LogLevel", 'L', FALSE,
1268 "MeToo", 'm', TRUE,
1269 "CheckAliases", 'n', FALSE,
1270 "OldStyleHeaders", 'o', TRUE,
1271 "DaemonPortOptions", 'O', FALSE,
1272 "PrivacyOptions", 'p', TRUE,
1273 "PostmasterCopy", 'P', FALSE,
1274 "QueueFactor", 'q', FALSE,
1275 "QueueDirectory", 'Q', FALSE,
1276 "DontPruneRoutes", 'R', FALSE,
4837d462 1277 "Timeout", 'r', TRUE,
6d04ef05
EA
1278 "StatusFile", 'S', FALSE,
1279 "SuperSafe", 's', TRUE,
1280 "QueueTimeout", 'T', FALSE,
1281 "TimeZoneSpec", 't', FALSE,
1282 "UserDatabaseSpec", 'U', FALSE,
1283 "DefaultUser", 'u', FALSE,
1284 "FallbackMXhost", 'V', FALSE,
1285 "Verbose", 'v', TRUE,
1286 "TryNullMXList", 'w', TRUE,
1287 "QueueLA", 'x', FALSE,
1288 "RefuseLA", 'X', FALSE,
1289 "RecipientFactor", 'y', FALSE,
d84bd6b5 1290 "ForkEachJob", 'Y', FALSE,
6d04ef05 1291 "ClassFactor", 'z', FALSE,
d84bd6b5 1292 "RetryFactor", 'Z', FALSE,
6d04ef05
EA
1293#define O_BSP 0x80
1294 "BrokenSmtpPeers", O_BSP, TRUE,
5b5e1c18 1295#define O_QUEUESORTORD 0x81
92830179 1296 "QueueSortOrder", O_QUEUESORTORD, TRUE,
6d04ef05
EA
1297#define O_MQA 0x83
1298 "MinQueueAge", O_MQA, TRUE,
1299#define O_MHSA 0x84
6bafe325 1300/*
6d04ef05 1301 "MaxHostStatAge", O_MHSA, TRUE,
6bafe325 1302*/
a50ac3e2
EA
1303#define O_DEFCHARSET 0x85
1304 "DefaultCharSet", O_DEFCHARSET, TRUE,
437376a9
EA
1305#define O_SSFILE 0x86
1306 "ServiceSwitchFile", O_SSFILE, FALSE,
8d7cd263
EA
1307#define O_DIALDELAY 0x87
1308 "DialDelay", O_DIALDELAY, TRUE,
d2780a78
EA
1309#define O_NORCPTACTION 0x88
1310 "NoRecipientAction", O_NORCPTACTION, TRUE,
99fd9645
EA
1311#define O_SAFEFILEENV 0x89
1312 "SafeFileEnvironment", O_SAFEFILEENV, FALSE,
d84bd6b5
EA
1313#define O_MAXMSGSIZE 0x8a
1314 "MaxMessageSize", O_MAXMSGSIZE, FALSE,
e7a9542d
EA
1315#define O_COLONOKINADDR 0x8b
1316 "ColonOkInAddr", O_COLONOKINADDR, TRUE,
6d04ef05
EA
1317
1318 NULL, '\0', FALSE,
2a58b3a7
EA
1319};
1320
1321
1322
46f6ec52 1323setoption(opt, val, sticky)
2a58b3a7 1324 u_char opt;
a691a4a6 1325 char *val;
c1e24818 1326 bool sticky;
8c8e8e94 1327 register ENVELOPE *e;
a691a4a6 1328{
ff87df81 1329 register char *p;
2a58b3a7 1330 register struct optioninfo *o;
168571ae 1331 char *subopt;
fbd53483 1332 extern bool atobool();
77b16ff1 1333 extern time_t convtime();
f7e74083
EA
1334 extern int QueueLA;
1335 extern int RefuseLA;
fe3849ea 1336 extern bool Warn_Q_option;
a691a4a6 1337
8c5f3d6c 1338 errno = 0;
2a58b3a7
EA
1339 if (opt == ' ')
1340 {
1341 /* full word options */
8c5f3d6c 1342 struct optioninfo *sel;
2a58b3a7
EA
1343
1344 p = strchr(val, '=');
1345 if (p == NULL)
1346 p = &val[strlen(val)];
1347 while (*--p == ' ')
1348 continue;
1349 while (*++p == ' ')
1350 *p = '\0';
834edebf
EA
1351 if (p == val)
1352 {
1353 syserr("readcf: null option name");
1354 return;
1355 }
2a58b3a7
EA
1356 if (*p == '=')
1357 *p++ = '\0';
1358 while (*p == ' ')
1359 p++;
168571ae
EA
1360 subopt = strchr(val, '.');
1361 if (subopt != NULL)
1362 *subopt++ = '\0';
8c5f3d6c 1363 sel = NULL;
2a58b3a7
EA
1364 for (o = OptionTab; o->o_name != NULL; o++)
1365 {
8c5f3d6c
EA
1366 if (strncasecmp(o->o_name, val, strlen(val)) != 0)
1367 continue;
1368 if (strlen(o->o_name) == strlen(val))
1369 {
1370 /* completely specified -- this must be it */
1371 sel = NULL;
2a58b3a7 1372 break;
8c5f3d6c
EA
1373 }
1374 if (sel != NULL)
1375 break;
1376 sel = o;
2a58b3a7 1377 }
8c5f3d6c
EA
1378 if (sel != NULL && o->o_name == NULL)
1379 o = sel;
1380 else if (o->o_name == NULL)
fddf2552 1381 {
2a58b3a7 1382 syserr("readcf: unknown option name %s", val);
fddf2552
EA
1383 return;
1384 }
8c5f3d6c
EA
1385 else if (sel != NULL)
1386 {
1387 syserr("readcf: ambiguous option name %s (matches %s and %s)",
1388 val, sel->o_name, o->o_name);
1389 return;
1390 }
1391 if (strlen(val) != strlen(o->o_name))
1392 {
1393 bool oldVerbose = Verbose;
1394
1395 Verbose = TRUE;
1396 message("Option %s used as abbreviation for %s",
1397 val, o->o_name);
1398 Verbose = oldVerbose;
1399 }
2a58b3a7
EA
1400 opt = o->o_code;
1401 val = p;
1402 }
1403 else
1404 {
1405 for (o = OptionTab; o->o_name != NULL; o++)
1406 {
1407 if (o->o_code == opt)
1408 break;
1409 }
168571ae 1410 subopt = NULL;
2a58b3a7
EA
1411 }
1412
a691a4a6 1413 if (tTd(37, 1))
834edebf
EA
1414 {
1415 printf(isascii(opt) && isprint(opt) ?
168571ae
EA
1416 "setoption %s (%c).%s=%s" :
1417 "setoption %s (0x%x).%s=%s",
2a58b3a7 1418 o->o_name == NULL ? "<unknown>" : o->o_name,
168571ae
EA
1419 opt,
1420 subopt == NULL ? "" : subopt,
1421 val);
834edebf 1422 }
a691a4a6
EA
1423
1424 /*
c1e24818
EA
1425 ** See if this option is preset for us.
1426 */
1427
82cc0371 1428 if (!sticky && bitnset(opt, StickyOpt))
c1e24818 1429 {
e6f08ab1
EA
1430 if (tTd(37, 1))
1431 printf(" (ignored)\n");
c1e24818
EA
1432 return;
1433 }
c1e24818 1434
46f6ec52 1435 if (tTd(37, 1))
bb09c502 1436 printf("\n");
c1e24818 1437
2a58b3a7 1438 switch (opt & 0xff)
a691a4a6 1439 {
a1925411
EA
1440 case '!': /* extended options */
1441 setextoption(val, safe, sticky, e);
1442 break;
1443
6a7569d3 1444 case '7': /* force seven-bit input */
c23930c0
EA
1445 SevenBitInput = atobool(val);
1446 break;
1447
1448 case '8': /* handling of 8-bit input */
1449 switch (*val)
1450 {
e3c84ea8 1451 case 'r': /* reject 8-bit, don't convert MIME */
c23930c0
EA
1452 MimeMode = 0;
1453 break;
1454
e3c84ea8 1455 case 'm': /* convert 8-bit, convert MIME */
c23930c0
EA
1456 MimeMode = MM_CVTMIME|MM_MIME8BIT;
1457 break;
1458
e3c84ea8 1459 case 'j': /* "just send 8" */
c23930c0
EA
1460 MimeMode = MM_PASS8BIT;
1461 break;
1462
1463 case 'p': /* pass 8 bit, convert MIME */
1464 MimeMode = MM_PASS8BIT|MM_CVTMIME;
1465 break;
1466
1467 case 's': /* strict adherence */
1468 MimeMode = MM_CVTMIME;
1469 break;
1470
e3c84ea8 1471 case 'a': /* encode 8 bit if available */
c23930c0
EA
1472 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
1473 break;
1474
e3c84ea8
EA
1475 case 'c': /* convert 8 bit to MIME, never 7 bit */
1476 MimeMode = MM_MIME8BIT;
1477 break;
1478
c23930c0
EA
1479 default:
1480 syserr("Unknown 8-bit mode %c", *val);
1481 exit(EX_USAGE);
1482 }
8657d05f
EA
1483 break;
1484
a691a4a6 1485 case 'A': /* set default alias file */
7338e3d4 1486 if (val[0] == '\0')
595aeb43 1487 setalias("aliases");
7338e3d4 1488 else
595aeb43 1489 setalias(val);
c1e24818
EA
1490 break;
1491
560a80d9
EA
1492 case 'a': /* look N minutes for "@:@" in alias file */
1493 if (val[0] == '\0')
e4f1022d 1494 SafeAlias = 5 * 60; /* five minutes */
560a80d9 1495 else
e4f1022d 1496 SafeAlias = convtime(val, 'm');
560a80d9
EA
1497 break;
1498
cbad72d2
EA
1499 case 'B': /* substitution for blank character */
1500 SpaceSub = val[0];
1501 if (SpaceSub == '\0')
1502 SpaceSub = ' ';
1503 break;
1504
00168067
EA
1505 case 'b': /* min blocks free on queue fs/max msg size */
1506 p = strchr(val, '/');
1507 if (p != NULL)
1508 {
1509 *p++ = '\0';
1510 MaxMessageSize = atol(p);
1511 }
1c7897ef
EA
1512 MinBlocksFree = atol(val);
1513 break;
1514
75f95954 1515 case 'c': /* don't connect to "expensive" mailers */
7338e3d4 1516 NoConnect = atobool(val);
75f95954
EA
1517 break;
1518
0f59c44f
EA
1519 case 'C': /* checkpoint every N addresses */
1520 CheckpointInterval = atoi(val);
2e3062fe
EA
1521 break;
1522
75f95954
EA
1523 case 'd': /* delivery mode */
1524 switch (*val)
c1e24818 1525 {
75f95954 1526 case '\0':
8c8e8e94 1527 e->e_sendmode = SM_DELIVER;
c1e24818
EA
1528 break;
1529
2ec2faaa
EA
1530 case SM_QUEUE: /* queue only */
1531#ifndef QUEUE
1532 syserr("need QUEUE to set -odqueue");
f3d8f6d6 1533#endif /* QUEUE */
2ec2faaa
EA
1534 /* fall through..... */
1535
75f95954
EA
1536 case SM_DELIVER: /* do everything */
1537 case SM_FORK: /* fork after verification */
8c8e8e94 1538 e->e_sendmode = *val;
c1e24818
EA
1539 break;
1540
1541 default:
75f95954 1542 syserr("Unknown delivery mode %c", *val);
c1e24818
EA
1543 exit(EX_USAGE);
1544 }
1545 break;
1546
43928995 1547 case 'D': /* rebuild alias database as needed */
7338e3d4 1548 AutoRebuild = atobool(val);
43928995
EA
1549 break;
1550
44967af8 1551 case 'E': /* error message header/header file */
01150349
EA
1552 if (*val != '\0')
1553 ErrMsgFile = newstr(val);
44967af8
EA
1554 break;
1555
c1e24818
EA
1556 case 'e': /* set error processing mode */
1557 switch (*val)
1558 {
7338e3d4 1559 case EM_QUIET: /* be silent about it */
7338e3d4
EA
1560 case EM_MAIL: /* mail back */
1561 case EM_BERKNET: /* do berknet error processing */
1562 case EM_WRITE: /* write back (or mail) */
7338e3d4 1563 case EM_PRINT: /* print errors normally (default) */
8c8e8e94 1564 e->e_errormode = *val;
c1e24818
EA
1565 break;
1566 }
1567 break;
1568
6db97a2f 1569 case 'F': /* file mode */
a8cef4da 1570 FileMode = atooct(val) & 0777;
6db97a2f
EA
1571 break;
1572
c1e24818 1573 case 'f': /* save Unix-style From lines on front */
7338e3d4 1574 SaveFrom = atobool(val);
a691a4a6
EA
1575 break;
1576
7f0fd60b
EA
1577 case 'G': /* match recipients against GECOS field */
1578 MatchGecos = atobool(val);
1579 break;
1580
a691a4a6 1581 case 'g': /* default gid */
cfc56dec 1582 g_opt:
6c87807d
EA
1583 if (isascii(*val) && isdigit(*val))
1584 DefGid = atoi(val);
1585 else
1586 {
1587 register struct group *gr;
1588
1589 DefGid = -1;
1590 gr = getgrnam(val);
1591 if (gr == NULL)
cfc56dec
EA
1592 syserr("readcf: option %c: unknown group %s",
1593 opt, val);
6c87807d
EA
1594 else
1595 DefGid = gr->gr_gid;
1596 }
a691a4a6
EA
1597 break;
1598
1599 case 'H': /* help file */
7338e3d4 1600 if (val[0] == '\0')
c1e24818 1601 HelpFile = "sendmail.hf";
7338e3d4
EA
1602 else
1603 HelpFile = newstr(val);
c1e24818
EA
1604 break;
1605
0f59c44f
EA
1606 case 'h': /* maximum hop count */
1607 MaxHopCount = atoi(val);
1608 break;
1609
35af2f06 1610 case 'I': /* use internet domain name server */
efe7f723 1611#if NAMED_BIND
ff87df81
EA
1612 for (p = val; *p != 0; )
1613 {
1614 bool clearmode;
1615 char *q;
1616 struct resolverflags *rfp;
1617
1618 while (*p == ' ')
1619 p++;
1620 if (*p == '\0')
1621 break;
1622 clearmode = FALSE;
1623 if (*p == '-')
1624 clearmode = TRUE;
1625 else if (*p != '+')
1626 p--;
1627 p++;
1628 q = p;
2bee003d 1629 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
ff87df81
EA
1630 p++;
1631 if (*p != '\0')
1632 *p++ = '\0';
25792b6f
EA
1633 if (strcasecmp(q, "HasWildcardMX") == 0)
1634 {
1635 NoMXforCanon = !clearmode;
1636 continue;
1637 }
ff87df81
EA
1638 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
1639 {
1640 if (strcasecmp(q, rfp->rf_name) == 0)
1641 break;
1642 }
736740b3
EA
1643 if (rfp->rf_name == NULL)
1644 syserr("readcf: I option value %s unrecognized", q);
1645 else if (clearmode)
ff87df81
EA
1646 _res.options &= ~rfp->rf_bits;
1647 else
1648 _res.options |= rfp->rf_bits;
1649 }
1650 if (tTd(8, 2))
25792b6f
EA
1651 printf("_res.options = %x, HasWildcardMX = %d\n",
1652 _res.options, !NoMXforCanon);
ff87df81
EA
1653#else
1654 usrerr("name server (I option) specified but BIND not compiled in");
1655#endif
35af2f06
EA
1656 break;
1657
c1e24818 1658 case 'i': /* ignore dot lines in message */
7338e3d4 1659 IgnrDot = atobool(val);
a691a4a6
EA
1660 break;
1661
2f6a8a78
EA
1662 case 'j': /* send errors in MIME (RFC 1341) format */
1663 SendMIMEErrors = atobool(val);
1664 break;
1665
e0136832
EA
1666 case 'J': /* .forward search path */
1667 ForwardPath = newstr(val);
1668 break;
1669
f2e44ded
EA
1670 case 'k': /* connection cache size */
1671 MaxMciCache = atoi(val);
5031c0bb
EA
1672 if (MaxMciCache < 0)
1673 MaxMciCache = 0;
f2e44ded
EA
1674 break;
1675
1676 case 'K': /* connection cache timeout */
1d136a1f 1677 MciCacheTimeout = convtime(val, 'm');
f2e44ded
EA
1678 break;
1679
91b43e7a
EA
1680 case 'l': /* use Errors-To: header */
1681 UseErrorsTo = atobool(val);
1682 break;
1683
a691a4a6 1684 case 'L': /* log level */
a81aa282
EA
1685 if (safe || LogLevel < atoi(val))
1686 LogLevel = atoi(val);
a691a4a6
EA
1687 break;
1688
c1e24818 1689 case 'M': /* define macro */
c244ef3c
EA
1690 p = newstr(&val[1]);
1691 if (!safe)
1692 cleanstrcpy(p, p, MAXNAME);
1693 define(val[0], p, CurEnv);
6385142f 1694 sticky = FALSE;
c1e24818
EA
1695 break;
1696
1697 case 'm': /* send to me too */
7338e3d4 1698 MeToo = atobool(val);
c1e24818
EA
1699 break;
1700
1e963db5
EA
1701 case 'n': /* validate RHS in newaliases */
1702 CheckAliases = atobool(val);
1703 break;
1704
91b43e7a
EA
1705 /* 'N' available -- was "net name" */
1706
7de9371a
EA
1707 case 'O': /* daemon options */
1708 setdaemonoptions(val);
1709 break;
1710
c1e24818 1711 case 'o': /* assume old style headers */
7338e3d4 1712 if (atobool(val))
e6f08ab1
EA
1713 CurEnv->e_flags |= EF_OLDSTYLE;
1714 else
1715 CurEnv->e_flags &= ~EF_OLDSTYLE;
c1e24818
EA
1716 break;
1717
1c7897ef
EA
1718 case 'p': /* select privacy level */
1719 p = val;
1720 for (;;)
1721 {
1722 register struct prival *pv;
1723 extern struct prival PrivacyValues[];
1724
1725 while (isascii(*p) && (isspace(*p) || ispunct(*p)))
1726 p++;
1727 if (*p == '\0')
1728 break;
1729 val = p;
1730 while (isascii(*p) && isalnum(*p))
1731 p++;
1732 if (*p != '\0')
1733 *p++ = '\0';
1734
1735 for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
1736 {
1737 if (strcasecmp(val, pv->pv_name) == 0)
1738 break;
1739 }
fa33a265
EA
1740 if (pv->pv_name == NULL)
1741 syserr("readcf: Op line: %s unrecognized", val);
1c7897ef
EA
1742 PrivacyFlags |= pv->pv_flag;
1743 }
6ecd3777 1744 sticky = FALSE;
1c7897ef
EA
1745 break;
1746
2e3062fe
EA
1747 case 'P': /* postmaster copy address for returned mail */
1748 PostMasterCopy = newstr(val);
1749 break;
1750
1751 case 'q': /* slope of queue only function */
1752 QueueFactor = atoi(val);
1753 break;
1754
a691a4a6 1755 case 'Q': /* queue directory */
7338e3d4 1756 if (val[0] == '\0')
c1e24818 1757 QueueDir = "mqueue";
7338e3d4
EA
1758 else
1759 QueueDir = newstr(val);
94bc039a 1760 if (RealUid != 0 && !safe)
fe3849ea 1761 Warn_Q_option = TRUE;
a691a4a6
EA
1762 break;
1763
2f7be259
EA
1764 case 'R': /* don't prune routes */
1765 DontPruneRoutes = atobool(val);
1766 break;
1767
a691a4a6 1768 case 'r': /* read timeout */
168571ae
EA
1769 if (subopt == NULL)
1770 inittimeouts(val);
1771 else
1772 settimeout(subopt, val);
a691a4a6
EA
1773 break;
1774
1775 case 'S': /* status file */
7338e3d4 1776 if (val[0] == '\0')
c1e24818 1777 StatFile = "sendmail.st";
7338e3d4
EA
1778 else
1779 StatFile = newstr(val);
a691a4a6
EA
1780 break;
1781
fbd53483 1782 case 's': /* be super safe, even if expensive */
7338e3d4 1783 SuperSafe = atobool(val);
a691a4a6 1784 break;
a691a4a6
EA
1785
1786 case 'T': /* queue timeout */
c2bdb1dd
EA
1787 p = strchr(val, '/');
1788 if (p != NULL)
1789 {
1790 *p++ = '\0';
168571ae 1791 settimeout("queuewarn", p);
c2bdb1dd 1792 }
168571ae 1793 settimeout("queuereturn", val);
f2e44ded 1794 break;
a691a4a6 1795
fbd53483 1796 case 't': /* time zone name */
8657d05f 1797 TimeZoneSpec = newstr(val);
fbd53483
EA
1798 break;
1799
8a12fae4 1800 case 'U': /* location of user database */
83b7c7b1 1801 UdbSpec = newstr(val);
8a12fae4
EA
1802 break;
1803
a691a4a6 1804 case 'u': /* set default uid */
cfc56dec
EA
1805 for (p = val; *p != '\0'; p++)
1806 {
1807 if (*p == '.' || *p == '/' || *p == ':')
1808 {
1809 *p++ = '\0';
1810 break;
1811 }
1812 }
6c87807d
EA
1813 if (isascii(*val) && isdigit(*val))
1814 DefUid = atoi(val);
1815 else
1816 {
1817 register struct passwd *pw;
1818
1819 DefUid = -1;
5b7a2dfe 1820 pw = sm_getpwnam(val);
6c87807d
EA
1821 if (pw == NULL)
1822 syserr("readcf: option u: unknown user %s", val);
1823 else
cfc56dec 1824 {
6c87807d 1825 DefUid = pw->pw_uid;
cfc56dec
EA
1826 DefGid = pw->pw_gid;
1827 }
6c87807d 1828 }
3fbc69d6 1829 setdefuser();
cfc56dec
EA
1830
1831 /* handle the group if it is there */
1832 if (*p == '\0')
1833 break;
1834 val = p;
1835 goto g_opt;
a691a4a6 1836
7de9371a
EA
1837 case 'V': /* fallback MX host */
1838 FallBackMX = newstr(val);
1839 break;
1840
c1e24818 1841 case 'v': /* run in verbose mode */
7338e3d4 1842 Verbose = atobool(val);
a691a4a6
EA
1843 break;
1844
392b4f58
EA
1845 case 'w': /* if we are best MX, try host directly */
1846 TryNullMXList = atobool(val);
1847 break;
91b43e7a
EA
1848
1849 /* 'W' available -- was wizard password */
1850
f7e74083
EA
1851 case 'x': /* load avg at which to auto-queue msgs */
1852 QueueLA = atoi(val);
1853 break;
1854
1855 case 'X': /* load avg at which to auto-reject connections */
1856 RefuseLA = atoi(val);
1857 break;
1858
a0225d08
EA
1859 case 'y': /* work recipient factor */
1860 WkRecipFact = atoi(val);
1861 break;
1862
1863 case 'Y': /* fork jobs during queue runs */
b51cc841
EA
1864 ForkQueueRuns = atobool(val);
1865 break;
1866
a0225d08
EA
1867 case 'z': /* work message class factor */
1868 WkClassFact = atoi(val);
1869 break;
1870
1871 case 'Z': /* work time factor */
1872 WkTimeFact = atoi(val);
1873 break;
1874
2a58b3a7
EA
1875 case O_BSP: /* SMTP Peers can't handle 2-line greeting */
1876 BrokenSmtpPeers = atobool(val);
1877 break;
1878
92830179
EA
1879 case O_QUEUESORTORD: /* queue sorting order */
1880 switch (*val)
1881 {
1882 case 'h': /* Host first */
1883 case 'H':
1884 QueueSortOrder = QS_BYHOST;
1885 break;
1886
1887 case 'p': /* Priority order */
1888 case 'P':
1889 QueueSortOrder = QS_BYPRIORITY;
1890 break;
1891
1892 default:
1893 syserr("Invalid queue sort order \"%s\"", val);
1894 }
2a58b3a7
EA
1895 break;
1896
6d04ef05
EA
1897 case O_MQA: /* minimum queue age between deliveries */
1898 MinQueueAge = convtime(val, 'm');
1899 break;
1900
1901 case O_MHSA: /* maximum age of cached host status */
1902 MaxHostStatAge = convtime(val, 'm');
1903 break;
1904
a50ac3e2 1905 case O_DEFCHARSET: /* default character set for mimefying */
b2af5ecf 1906 DefaultCharSet = newstr(denlstring(val, TRUE, TRUE));
a50ac3e2
EA
1907 break;
1908
437376a9
EA
1909 case O_SSFILE: /* service switch file */
1910 ServiceSwitchFile = newstr(val);
1911 break;
1912
8d7cd263
EA
1913 case O_DIALDELAY: /* delay for dial-on-demand operation */
1914 DialDelay = convtime(val, 's');
1915 break;
1916
d2780a78
EA
1917 case O_NORCPTACTION: /* what to do if no recipient */
1918 if (strcasecmp(val, "none") == 0)
1919 NoRecipientAction = NRA_NO_ACTION;
1920 else if (strcasecmp(val, "add-to") == 0)
1921 NoRecipientAction = NRA_ADD_TO;
1922 else if (strcasecmp(val, "add-apparently-to") == 0)
1923 NoRecipientAction = NRA_ADD_APPARENTLY_TO;
1924 else if (strcasecmp(val, "add-bcc") == 0)
1925 NoRecipientAction = NRA_ADD_BCC;
1926 else if (strcasecmp(val, "add-to-undisclosed") == 0)
1927 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
1928 else
1929 syserr("Invalid NoRecipientAction: %s", val);
1930
99fd9645
EA
1931 case O_SAFEFILEENV: /* chroot() environ for writing to files */
1932 SafeFileEnv = newstr(val);
1933 break;
1934
d84bd6b5
EA
1935 case O_MAXMSGSIZE: /* maximum message size */
1936 MaxMessageSize = atol(p);
1937 break;
1938
e7a9542d
EA
1939 case O_COLONOKINADDR: /* old style handling of colon addresses */
1940 ColonOkInAddr = atobool(p);
1941 break;
1942
a691a4a6 1943 default:
6bafe325
EA
1944 if (tTd(37, 1))
1945 {
1946 if (isascii(opt) && isprint(opt))
1947 printf("Warning: option %c unknown\n", opt);
1948 else
1949 printf("Warning: option 0x%x unknown\n", opt);
1950 }
a691a4a6
EA
1951 break;
1952 }
6385142f
EA
1953 if (sticky)
1954 setbitn(opt, StickyOpt);
d985aa86 1955 return;
a691a4a6 1956}
1dbda134 1957\f/*
a1925411
EA
1958** SETEXTOPTION -- set extended option
1959**
1960** This is a bogus attempt to do what sendmail should have done
1961** in the first place. Parses "name=value" options.
1962**
1963** Parameters:
1964** opt -- pointer to the string option.
1965** safe -- from setoption.
1966** sticky -- from setoption.
1967** e -- the envelope.
1968**
1969** Returns:
1970** none.
1971*/
1972
1973struct extopts
1974{
1975 char *xo_name; /* option name */
1976 short xo_code; /* option code */
1977 short xo_flags; /* flag bits */
1978};
1979
1980/* bits for xo_flags */
1981#define XOF_SAFE 0x0001 /* this option is safe */
1982#define XOF_STICKY 0x0100 /* this option has been given & is sticky */
1983
1984struct extopts ExtOpts[] =
1985{
1986#define XO_TRYNULLMXLIST 1
1987 "trynullmxlist", XO_TRYNULLMXLIST, XOF_SAFE,
1988#define XO_MAXCODE 1
1989 NULL, -1, 0
1990};
1991
1992
1993setextoption(opt, safe, sticky, e)
1994 register char *opt;
1995 bool safe;
1996 bool sticky;
1997 register ENVELOPE *e;
1998{
1999 register char *val;
2000 register struct extopts *xo;
2001 extern bool atobool();
2002
2003 val = strchr(opt, '=');
2004 if (val != NULL)
2005 *val++ = '\0';
2006
2007 for (xo = ExtOpts; xo->xo_name != NULL; xo++)
2008 {
2009 if (strcasecmp(xo->xo_name, opt) == 0)
2010 break;
2011 }
2012
2013 if (!sticky && bitset(XOF_STICKY, xo->xo_flags))
2014 return;
2015
2016 if (!safe && !bitset(XOF_SAFE, xo->xo_flags))
2017 {
2018 if (RealUid != geteuid())
2019 {
2020 (void) setgid(RealGid);
2021 (void) setuid(RealUid);
2022 }
2023 }
2024
2025 switch (xo->xo_code)
2026 {
2027 case XO_TRYNULLMXLIST:
2028 TryNullMXList = atobool(val);
2029 break;
2030
2031 default:
2032 syserr("Unknown extended option \"%s\"", opt);
2033 return;
2034 }
2035
2036 if (sticky)
2037 xo->xo_flags |= XOF_STICKY;
2038}
2039\f/*
1ead4c2f 2040** SETCLASS -- set a string into a class
1dbda134
EA
2041**
2042** Parameters:
1ead4c2f
EA
2043** class -- the class to put the string in.
2044** str -- the string to enter
1dbda134
EA
2045**
2046** Returns:
2047** none.
2048**
2049** Side Effects:
2050** puts the word into the symbol table.
2051*/
2052
1ead4c2f 2053setclass(class, str)
1dbda134 2054 int class;
1ead4c2f 2055 char *str;
1dbda134
EA
2056{
2057 register STAB *s;
2058
322eceee 2059 if (tTd(37, 8))
1ead4c2f
EA
2060 printf("setclass(%c, %s)\n", class, str);
2061 s = stab(str, ST_CLASS, ST_ENTER);
1dbda134
EA
2062 setbitn(class, s->s_class);
2063}
42fa5d67
EA
2064\f/*
2065** MAKEMAPENTRY -- create a map entry
2066**
2067** Parameters:
2068** line -- the config file line
2069**
2070** Returns:
2071** TRUE if it successfully entered the map entry.
2072** FALSE otherwise (usually syntax error).
2073**
2074** Side Effects:
2075** Enters the map into the dictionary.
2076*/
2077
2078void
2079makemapentry(line)
2080 char *line;
2081{
2082 register char *p;
2083 char *mapname;
2084 char *classname;
9d39f599 2085 register STAB *s;
42fa5d67
EA
2086 STAB *class;
2087
2bee003d 2088 for (p = line; isascii(*p) && isspace(*p); p++)
42fa5d67 2089 continue;
2bee003d 2090 if (!(isascii(*p) && isalnum(*p)))
42fa5d67
EA
2091 {
2092 syserr("readcf: config K line: no map name");
2093 return;
2094 }
2095
2096 mapname = p;
437376a9 2097 while ((isascii(*++p) && isalnum(*p)) || *p == '.')
42fa5d67
EA
2098 continue;
2099 if (*p != '\0')
2100 *p++ = '\0';
2bee003d 2101 while (isascii(*p) && isspace(*p))
42fa5d67 2102 p++;
2bee003d 2103 if (!(isascii(*p) && isalnum(*p)))
42fa5d67
EA
2104 {
2105 syserr("readcf: config K line, map %s: no map class", mapname);
2106 return;
2107 }
2108 classname = p;
2bee003d 2109 while (isascii(*++p) && isalnum(*p))
42fa5d67
EA
2110 continue;
2111 if (*p != '\0')
2112 *p++ = '\0';
2bee003d 2113 while (isascii(*p) && isspace(*p))
42fa5d67
EA
2114 p++;
2115
2116 /* look up the class */
2117 class = stab(classname, ST_MAPCLASS, ST_FIND);
2118 if (class == NULL)
2119 {
2120 syserr("readcf: map %s: class %s not available", mapname, classname);
2121 return;
2122 }
2123
2124 /* enter the map */
9d39f599
EA
2125 s = stab(mapname, ST_MAP, ST_ENTER);
2126 s->s_map.map_class = &class->s_mapclass;
2127 s->s_map.map_mname = newstr(mapname);
2128
2129 if (class->s_mapclass.map_parse(&s->s_map, p))
2130 s->s_map.map_mflags |= MF_VALID;
42fa5d67 2131
9d39f599
EA
2132 if (tTd(37, 5))
2133 {
2134 printf("map %s, class %s, flags %x, file %s,\n",
2135 s->s_map.map_mname, s->s_map.map_class->map_cname,
2136 s->s_map.map_mflags,
2137 s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
2138 printf("\tapp %s, domain %s, rebuild %s\n",
2139 s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
2140 s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
2141 s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
2142 }
42fa5d67 2143}
7f5e2eef 2144\f/*
168571ae 2145** INITTIMEOUTS -- parse and set timeout values
7f5e2eef
EA
2146**
2147** Parameters:
2148** val -- a pointer to the values. If NULL, do initial
2149** settings.
2150**
2151** Returns:
2152** none.
2153**
2154** Side Effects:
2155** Initializes the TimeOuts structure
2156*/
2157
cf7a936d 2158#define SECONDS
7f5e2eef
EA
2159#define MINUTES * 60
2160#define HOUR * 3600
2161
168571ae 2162inittimeouts(val)
7f5e2eef
EA
2163 register char *val;
2164{
2165 register char *p;
16133a1c 2166 extern time_t convtime();
7f5e2eef
EA
2167
2168 if (val == NULL)
2169 {
2170 TimeOuts.to_initial = (time_t) 5 MINUTES;
2171 TimeOuts.to_helo = (time_t) 5 MINUTES;
2172 TimeOuts.to_mail = (time_t) 10 MINUTES;
2173 TimeOuts.to_rcpt = (time_t) 1 HOUR;
2174 TimeOuts.to_datainit = (time_t) 5 MINUTES;
2175 TimeOuts.to_datablock = (time_t) 1 HOUR;
2176 TimeOuts.to_datafinal = (time_t) 1 HOUR;
2177 TimeOuts.to_rset = (time_t) 5 MINUTES;
2178 TimeOuts.to_quit = (time_t) 2 MINUTES;
2179 TimeOuts.to_nextcommand = (time_t) 1 HOUR;
2180 TimeOuts.to_miscshort = (time_t) 2 MINUTES;
8ec24e6b 2181#if IDENTPROTO
cf7a936d 2182 TimeOuts.to_ident = (time_t) 30 SECONDS;
8ec24e6b
EA
2183#else
2184 TimeOuts.to_ident = (time_t) 0 SECONDS;
2185#endif
039f3bb5 2186 TimeOuts.to_fileopen = (time_t) 60 SECONDS;
7f5e2eef
EA
2187 return;
2188 }
2189
2190 for (;; val = p)
2191 {
2192 while (isascii(*val) && isspace(*val))
2193 val++;
2194 if (*val == '\0')
2195 break;
2196 for (p = val; *p != '\0' && *p != ','; p++)
2197 continue;
2198 if (*p != '\0')
2199 *p++ = '\0';
2200
2201 if (isascii(*val) && isdigit(*val))
2202 {
2203 /* old syntax -- set everything */
1d136a1f 2204 TimeOuts.to_mail = convtime(val, 'm');
7f5e2eef
EA
2205 TimeOuts.to_rcpt = TimeOuts.to_mail;
2206 TimeOuts.to_datainit = TimeOuts.to_mail;
2207 TimeOuts.to_datablock = TimeOuts.to_mail;
2208 TimeOuts.to_datafinal = TimeOuts.to_mail;
2209 TimeOuts.to_nextcommand = TimeOuts.to_mail;
2210 continue;
2211 }
2212 else
2213 {
039f3bb5 2214 register char *q = strchr(val, ':');
7f5e2eef 2215
039f3bb5 2216 if (q == NULL && (q = strchr(val, '=')) == NULL)
7f5e2eef
EA
2217 {
2218 /* syntax error */
2219 continue;
2220 }
2221 *q++ = '\0';
168571ae 2222 settimeout(val, q);
7f5e2eef
EA
2223 }
2224 }
2225}
168571ae
EA
2226\f/*
2227** SETTIMEOUT -- set an individual timeout
2228**
2229** Parameters:
2230** name -- the name of the timeout.
2231** val -- the value of the timeout.
2232**
2233** Returns:
2234** none.
2235*/
2236
2237settimeout(name, val)
2238 char *name;
2239 char *val;
2240{
2241 register char *p;
2242 time_t to;
2243 extern time_t convtime();
2244
2245 to = convtime(val, 'm');
2246 p = strchr(name, '.');
2247 if (p != NULL)
2248 *p++ = '\0';
2249
2250 if (strcasecmp(name, "initial") == 0)
2251 TimeOuts.to_initial = to;
2252 else if (strcasecmp(name, "mail") == 0)
2253 TimeOuts.to_mail = to;
2254 else if (strcasecmp(name, "rcpt") == 0)
2255 TimeOuts.to_rcpt = to;
2256 else if (strcasecmp(name, "datainit") == 0)
2257 TimeOuts.to_datainit = to;
2258 else if (strcasecmp(name, "datablock") == 0)
2259 TimeOuts.to_datablock = to;
2260 else if (strcasecmp(name, "datafinal") == 0)
2261 TimeOuts.to_datafinal = to;
2262 else if (strcasecmp(name, "command") == 0)
2263 TimeOuts.to_nextcommand = to;
2264 else if (strcasecmp(name, "rset") == 0)
2265 TimeOuts.to_rset = to;
2266 else if (strcasecmp(name, "helo") == 0)
2267 TimeOuts.to_helo = to;
2268 else if (strcasecmp(name, "quit") == 0)
2269 TimeOuts.to_quit = to;
2270 else if (strcasecmp(name, "misc") == 0)
2271 TimeOuts.to_miscshort = to;
2272 else if (strcasecmp(name, "ident") == 0)
2273 TimeOuts.to_ident = to;
2274 else if (strcasecmp(name, "fileopen") == 0)
2275 TimeOuts.to_fileopen = to;
2276 else if (strcasecmp(name, "queuewarn") == 0)
2277 {
2278 to = convtime(val, 'h');
ad36a408 2279 if (p == NULL || strcmp(p, "*") == 0)
168571ae
EA
2280 {
2281 TimeOuts.to_q_warning[TOC_NORMAL] = to;
2282 TimeOuts.to_q_warning[TOC_URGENT] = to;
2283 TimeOuts.to_q_warning[TOC_NONURGENT] = to;
2284 }
2285 else if (strcasecmp(p, "normal") == 0)
2286 TimeOuts.to_q_warning[TOC_NORMAL] = to;
2287 else if (strcasecmp(p, "urgent") == 0)
2288 TimeOuts.to_q_warning[TOC_URGENT] = to;
2289 else if (strcasecmp(p, "non-urgent") == 0)
2290 TimeOuts.to_q_warning[TOC_NONURGENT] = to;
2291 else
2292 syserr("settimeout: invalid queuewarn subtimeout %s", p);
2293 }
2294 else if (strcasecmp(name, "queuereturn") == 0)
2295 {
2296 to = convtime(val, 'd');
2297 if (p == NULL || strcmp(p, "*") == 0)
2298 {
2299 TimeOuts.to_q_return[TOC_NORMAL] = to;
2300 TimeOuts.to_q_return[TOC_URGENT] = to;
2301 TimeOuts.to_q_return[TOC_NONURGENT] = to;
2302 }
2303 else if (strcasecmp(p, "normal") == 0)
2304 TimeOuts.to_q_return[TOC_NORMAL] = to;
2305 else if (strcasecmp(p, "urgent") == 0)
2306 TimeOuts.to_q_return[TOC_URGENT] = to;
2307 else if (strcasecmp(p, "non-urgent") == 0)
2308 TimeOuts.to_q_return[TOC_NONURGENT] = to;
2309 else
2310 syserr("settimeout: invalid queuereturn subtimeout %s", p);
2311 }
2312 else
2313 syserr("settimeout: invalid timeout %s", name);
2314}