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