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