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