1 /*
2 * Copyright (c) 1998-2006, 2008-2010, 2013 Proofpoint, Inc. and its suppliers.
3 * All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14 #include <sendmail.h>
15 #include <sm/sendmail.h>
16 #if STARTTLS
17 # include <tls.h>
18 #endif
19 #if DNSSEC_TEST || _FFR_NAMESERVER
20 # include "sm_resolve.h"
21 #endif
22
23 SM_RCSID("@(#)$Id: readcf.c,v 8.692 2013-11-22 20:51:56 ca Exp $")
24
25 #if NETINET || NETINET6
26 # include <arpa/inet.h>
27 #endif
28
29
30 #define SECONDS
31 #define MINUTES * 60
32 #define HOUR * 3600
33 #define HOURS HOUR
34
35 static void fileclass __P((int, char *, char *, bool, bool, bool));
36 #if _FFR_DYN_CLASS
37 static void dynclass __P((int, char *));
38 #endif
39 static char **makeargv __P((char *));
40 static void settimeout __P((char *, char *, bool));
41 static void toomany __P((int, int));
42 static char *extrquotstr __P((char *, char **, char *, bool *));
43 static void parse_class_words __P((int, char *));
44
45 #if _FFR_CLASS_RM_ENTRY
46 static void classrmentry __P((int, char *));
47 #endif
48
49 #if _FFR_BOUNCE_QUEUE
50 static char *bouncequeue = NULL;
51 static void initbouncequeue __P((void));
52
53 /*
54 ** INITBOUNCEQUEUE -- determine BounceQueue if option is set.
55 **
56 ** Parameters:
57 ** none.
58 **
59 ** Returns:
60 ** none.
61 **
62 ** Side Effects:
63 ** sets BounceQueue
64 */
65
66 static void
initbouncequeue()67 initbouncequeue()
68 {
69 STAB *s;
70
71 BounceQueue = NOQGRP;
72 if (SM_IS_EMPTY(bouncequeue))
73 return;
74
75 s = stab(bouncequeue, ST_QUEUE, ST_FIND);
76 if (s == NULL)
77 {
78 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
79 "Warning: option BounceQueue: unknown queue group %s\n",
80 bouncequeue);
81 }
82 else
83 BounceQueue = s->s_quegrp->qg_index;
84 }
85 #endif /* _FFR_BOUNCE_QUEUE */
86
87 #if _FFR_RCPTFLAGS
88 void setupdynmailers __P((void));
89 #else
90 #define setupdynmailers()
91 #endif
92
93 /*
94 ** READCF -- read configuration file.
95 **
96 ** This routine reads the configuration file and builds the internal
97 ** form.
98 **
99 ** The file is formatted as a sequence of lines, each taken
100 ** atomically. The first character of each line describes how
101 ** the line is to be interpreted. The lines are:
102 ** Dxval Define macro x to have value val.
103 ** Cxword Put word into class x.
104 ** Fxfile [fmt] Read file for lines to put into
105 ** class x. Use scanf string 'fmt'
106 ** or "%s" if not present. Fmt should
107 ** only produce one string-valued result.
108 ** Hname: value Define header with field-name 'name'
109 ** and value as specified; this will be
110 ** macro expanded immediately before
111 ** use.
112 ** Sn Use rewriting set n.
113 ** Rlhs rhs Rewrite addresses that match lhs to
114 ** be rhs.
115 ** Mn arg=val... Define mailer. n is the internal name.
116 ** Args specify mailer parameters.
117 ** Oxvalue Set option x to value.
118 ** O option value Set option (long name) to value.
119 ** Pname=value Set precedence name to value.
120 ** Qn arg=val... Define queue groups. n is the internal name.
121 ** Args specify queue parameters.
122 ** Vversioncode[/vendorcode]
123 ** Version level/vendor name of
124 ** configuration syntax.
125 ** Kmapname mapclass arguments....
126 ** Define keyed lookup of a given class.
127 ** Arguments are class dependent.
128 ** Eenvar=value Set the environment value to the given value.
129 **
130 ** Parameters:
131 ** cfname -- configuration file name.
132 ** safe -- true if this is the system config file;
133 ** false otherwise.
134 ** e -- the main envelope.
135 **
136 ** Returns:
137 ** none.
138 **
139 ** Side Effects:
140 ** Builds several internal tables.
141 */
142
143 void
readcf(cfname,safe,e)144 readcf(cfname, safe, e)
145 char *cfname;
146 bool safe;
147 register ENVELOPE *e;
148 {
149 SM_FILE_T *cf;
150 int ruleset = -1;
151 char *q;
152 struct rewrite *rwp = NULL;
153 char *bp;
154 auto char *ep;
155 int nfuzzy;
156 char *file;
157 bool optional;
158 bool ok;
159 bool ismap;
160 int mid;
161 register char *p;
162 long sff = SFF_OPENASROOT;
163 struct stat statb;
164 char buf[MAXLINE];
165 int bufsize;
166 char exbuf[MAXLINE];
167 char pvpbuf[MAXLINE + MAXATOM];
168 static char *null_list[1] = { NULL };
169 extern unsigned char TokTypeNoC[];
170 #if _FFR_CLASS_RM_ENTRY
171 int off;
172 #else
173 # define off 1
174 #endif
175
176 FileName = cfname;
177 LineNumber = 0;
178
179 if (DontLockReadFiles)
180 sff |= SFF_NOLOCK;
181 cf = safefopen(cfname, O_RDONLY, 0444, sff);
182 if (cf == NULL)
183 {
184 syserr("cannot open");
185 finis(false, true, EX_OSFILE);
186 }
187
188 if (fstat(sm_io_getinfo(cf, SM_IO_WHAT_FD, NULL), &statb) < 0)
189 {
190 syserr("cannot fstat");
191 finis(false, true, EX_OSFILE);
192 }
193
194 if (!S_ISREG(statb.st_mode))
195 {
196 syserr("not a plain file");
197 finis(false, true, EX_OSFILE);
198 }
199
200 if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
201 {
202 if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS || OpMode == MD_CHECKCONFIG)
203 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
204 "%s: WARNING: dangerous write permissions\n",
205 FileName);
206 if (LogLevel > 0)
207 sm_syslog(LOG_CRIT, NOQID,
208 "%s: WARNING: dangerous write permissions",
209 FileName);
210 }
211
212 #if XLA
213 xla_zero();
214 #endif
215
216 while (bufsize = sizeof(buf),
217 (bp = fgetfolded(buf, &bufsize, cf)) != NULL)
218 {
219 char *nbp;
220
221 if (bp[0] == '#')
222 {
223 if (bp != buf)
224 sm_free(bp); /* XXX */
225 continue;
226 }
227
228 /* do macro expansion mappings */
229 nbp = translate_dollars(bp, bp, &bufsize);
230 if (nbp != bp && bp != buf)
231 sm_free(bp);
232 bp = nbp;
233
234 /* interpret this line */
235 errno = 0;
236 switch (bp[0])
237 {
238 case '\0':
239 case '#': /* comment */
240 break;
241
242 case 'R': /* rewriting rule */
243 if (ruleset < 0)
244 {
245 syserr("missing valid ruleset for \"%s\"", bp);
246 break;
247 }
248 for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
249 continue;
250
251 if (*p == '\0')
252 {
253 syserr("invalid rewrite line \"%s\" (tab expected)", bp);
254 break;
255 }
256
257 /* allocate space for the rule header */
258 if (rwp == NULL)
259 {
260 RewriteRules[ruleset] = rwp =
261 (struct rewrite *) sm_malloc_tagged_x(sizeof(*rwp),
262 "rwr1", 1, 0);
263 }
264 else
265 {
266 rwp->r_next = (struct rewrite *) sm_malloc_tagged_x(sizeof(*rwp),
267 "rwr2", 2, 0);
268 rwp = rwp->r_next;
269 }
270 rwp->r_next = NULL;
271
272 /* expand and save the LHS */
273 *p = '\0';
274 expand(&bp[1], exbuf, sizeof(exbuf), e);
275 rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
276 sizeof(pvpbuf), NULL,
277 ConfigLevel >= 9 ? TokTypeNoC : IntTokenTab,
278 true);
279 nfuzzy = 0;
280 if (rwp->r_lhs != NULL)
281 {
282 register char **ap;
283
284 rwp->r_lhs = copyplist(rwp->r_lhs, true, NULL);
285
286 /* count the number of fuzzy matches in LHS */
287 for (ap = rwp->r_lhs; *ap != NULL; ap++)
288 {
289 char *botch;
290
291 botch = NULL;
292 switch (ap[0][0] & 0377)
293 {
294 case MATCHZANY:
295 case MATCHANY:
296 case MATCHONE:
297 case MATCHCLASS:
298 case MATCHNCLASS:
299 nfuzzy++;
300 break;
301
302 case MATCHREPL:
303 botch = "$1-$9";
304 break;
305
306 case CANONUSER:
307 botch = "$:";
308 break;
309
310 case CALLSUBR:
311 botch = "$>";
312 break;
313
314 case CONDIF:
315 botch = "$?";
316 break;
317
318 case CONDFI:
319 botch = "$.";
320 break;
321
322 case HOSTBEGIN:
323 botch = "$[";
324 break;
325
326 case HOSTEND:
327 botch = "$]";
328 break;
329
330 case LOOKUPBEGIN:
331 botch = "$(";
332 break;
333
334 case LOOKUPEND:
335 botch = "$)";
336 break;
337 }
338 if (botch != NULL)
339 syserr("Inappropriate use of %s on LHS",
340 botch);
341 }
342 rwp->r_line = LineNumber;
343 }
344 else
345 {
346 syserr("R line: null LHS");
347 rwp->r_lhs = null_list;
348 }
349 if (nfuzzy > MAXMATCH)
350 {
351 syserr("R line: too many wildcards");
352 rwp->r_lhs = null_list;
353 }
354
355 /* expand and save the RHS */
356 while (*++p == '\t')
357 continue;
358 q = p;
359 while (*p != '\0' && *p != '\t')
360 p++;
361 *p = '\0';
362 expand(q, exbuf, sizeof(exbuf), e);
363 rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
364 sizeof(pvpbuf), NULL,
365 ConfigLevel >= 9 ? TokTypeNoC : IntTokenTab,
366 true);
367 if (rwp->r_rhs != NULL)
368 {
369 register char **ap;
370 int args, endtoken;
371 #if _FFR_EXTRA_MAP_CHECK
372 int nexttoken;
373 #endif
374 bool inmap;
375
376 rwp->r_rhs = copyplist(rwp->r_rhs, true, NULL);
377
378 /* check no out-of-bounds replacements */
379 nfuzzy += '0';
380 inmap = false;
381 args = 0;
382 endtoken = 0;
383 for (ap = rwp->r_rhs; *ap != NULL; ap++)
384 {
385 char *botch;
386
387 botch = NULL;
388 switch (ap[0][0] & 0377)
389 {
390 case MATCHREPL:
391 if (ap[0][1] <= '0' ||
392 ap[0][1] > nfuzzy)
393 {
394 syserr("replacement $%c out of bounds",
395 ap[0][1]);
396 }
397 break;
398
399 case MATCHZANY:
400 botch = "$*";
401 break;
402
403 case MATCHANY:
404 botch = "$+";
405 break;
406
407 case MATCHONE:
408 botch = "$-";
409 break;
410
411 case MATCHCLASS:
412 botch = "$=";
413 break;
414
415 case MATCHNCLASS:
416 botch = "$~";
417 break;
418
419 case CANONHOST:
420 if (!inmap)
421 break;
422 if (++args >= MAX_MAP_ARGS)
423 syserr("too many arguments for map lookup");
424 break;
425
426 case HOSTBEGIN:
427 endtoken = HOSTEND;
428 /* FALLTHROUGH */
429 case LOOKUPBEGIN:
430 /* see above... */
431 if ((ap[0][0] & 0377) == LOOKUPBEGIN)
432 endtoken = LOOKUPEND;
433 if (inmap)
434 syserr("cannot nest map lookups");
435 inmap = true;
436 args = 0;
437 #if _FFR_EXTRA_MAP_CHECK
438 if (ap[1] == NULL)
439 {
440 syserr("syntax error in map lookup");
441 break;
442 }
443 nexttoken = ap[1][0] & 0377;
444 if (nexttoken == CANONHOST ||
445 nexttoken == CANONUSER ||
446 nexttoken == endtoken)
447 {
448 syserr("missing map name for lookup");
449 break;
450 }
451 if (ap[2] == NULL)
452 {
453 syserr("syntax error in map lookup");
454 break;
455 }
456 if ((unsigned char) ap[0][0] == HOSTBEGIN)
457 break;
458 nexttoken = ap[2][0] & 0377;
459 if (nexttoken == CANONHOST ||
460 nexttoken == CANONUSER ||
461 nexttoken == endtoken)
462 {
463 syserr("missing key name for lookup");
464 break;
465 }
466 #endif /* _FFR_EXTRA_MAP_CHECK */
467 break;
468
469 case HOSTEND:
470 case LOOKUPEND:
471 if ((ap[0][0] & 0377) != endtoken)
472 break;
473 inmap = false;
474 endtoken = 0;
475 break;
476
477 #if 0
478 /*
479 ** This doesn't work yet as there are maps defined *after* the cf
480 ** is read such as host, user, and alias. So for now, it's removed.
481 ** When it comes back, the RELEASE_NOTES entry will be:
482 ** Emit warnings for unknown maps when reading the .cf file. Based on
483 ** patch from Robert Harker of Harker Systems.
484 */
485
486 case LOOKUPBEGIN:
487 /*
488 ** Got a database lookup,
489 ** check if map is defined.
490 */
491
492 ep = ap[1];
493 if ((ep[0] & 0377) != MACRODEXPAND &&
494 stab(ep, ST_MAP, ST_FIND) == NULL)
495 {
496 (void) sm_io_fprintf(smioout,
497 SM_TIME_DEFAULT,
498 "Warning: %s: line %d: map %s not found\n",
499 FileName,
500 LineNumber,
501 ep);
502 }
503 break;
504 #endif /* 0 */
505 }
506 if (botch != NULL)
507 syserr("Inappropriate use of %s on RHS",
508 botch);
509 }
510 if (inmap)
511 syserr("missing map closing token");
512 }
513 else
514 {
515 syserr("R line: null RHS");
516 rwp->r_rhs = null_list;
517 }
518 break;
519
520 case 'S': /* select rewriting set */
521 expand(&bp[1], exbuf, sizeof(exbuf), e);
522 ruleset = strtorwset(exbuf, NULL, ST_ENTER);
523 if (ruleset < 0)
524 break;
525
526 rwp = RewriteRules[ruleset];
527 if (rwp != NULL)
528 {
529 if (OpMode == MD_TEST || OpMode == MD_CHECKCONFIG)
530 (void) sm_io_fprintf(smioout,
531 SM_TIME_DEFAULT,
532 "WARNING: Ruleset %s has multiple definitions\n",
533 &bp[1]);
534 if (tTd(37, 1))
535 sm_dprintf("WARNING: Ruleset %s has multiple definitions\n",
536 &bp[1]);
537 while (rwp->r_next != NULL)
538 rwp = rwp->r_next;
539 }
540 break;
541
542 case 'D': /* macro definition */
543 mid = macid_parse(&bp[1], &ep);
544 if (mid == 0)
545 break;
546 #if USE_EAI && 0
547 // if ('j' == mid && !addr_is_ascii(ep))
548 // {
549 // usrerr("hostname %s must be ASCII", ep);
550 // finis(false, true, EX_CONFIG);
551 // /* NOTREACHED */
552 // }
553 #endif
554 p = munchstring(ep, NULL, '\0');
555 macdefine(&e->e_macro, A_TEMP, mid, p);
556 break;
557
558 case 'H': /* required header line */
559 (void) chompheader(&bp[1], CHHDR_DEF, NULL, e);
560 break;
561
562 case 'C': /* word class */
563 case 'T': /* trusted user (set class `t') */
564 #if _FFR_CLASS_RM_ENTRY
565 if (bp[0] != '\0' && bp[1] == '-')
566 off = 2;
567 else
568 off = 1;
569 #endif
570 if (bp[0] == 'C')
571 {
572 mid = macid_parse(&bp[off], &ep);
573 if (mid == 0)
574 break;
575 expand(ep, exbuf, sizeof(exbuf), e);
576 p = exbuf;
577 #if _FFR_8BITENVADDR
578 dequote_internal_chars(p, exbuf, sizeof(exbuf));
579 #endif
580 }
581 else
582 {
583 mid = 't';
584 p = &bp[off];
585 }
586 while (*p != '\0')
587 {
588 register char *wd;
589 char delim;
590
591 while (*p != '\0' && SM_ISSPACE(*p))
592 p++;
593 wd = p;
594 while (*p != '\0' && !(SM_ISSPACE(*p)))
595 p++;
596 delim = *p;
597 *p = '\0';
598 if (wd[0] != '\0')
599 {
600 if (off < 2)
601 setclass(mid, wd);
602 #if _FFR_CLASS_RM_ENTRY
603 else
604 classrmentry(mid, wd);
605 #endif /* _FFR_CLASS_RM_ENTRY */
606 }
607 *p = delim;
608 }
609 break;
610
611 #if _FFR_DYN_CLASS
612 case 'A': /* dynamic class */
613 mid = macid_parse(&bp[1], &ep);
614 if (mid == 0)
615 break;
616 for (p = ep; SM_ISSPACE(*p); )
617 p++;
618 dynclass(mid, p);
619 break;
620 #endif
621
622 case 'F': /* word class from file */
623 mid = macid_parse(&bp[1], &ep);
624 if (mid == 0)
625 break;
626 for (p = ep; SM_ISSPACE(*p); )
627 p++;
628 if (p[0] == '-' && p[1] == 'o')
629 {
630 optional = true;
631 while (*p != '\0' &&
632 !(SM_ISSPACE(*p)))
633 p++;
634 while (SM_ISSPACE(*p))
635 p++;
636 }
637 else
638 optional = false;
639
640 /* check if [key]@map:spec */
641 ismap = false;
642 if (!SM_IS_DIR_DELIM(*p) &&
643 *p != '|' &&
644 (q = strchr(p, '@')) != NULL)
645 {
646 q++;
647
648 /* look for @LDAP or @map: in string */
649 if (strcmp(q, "LDAP") == 0 ||
650 (*q != ':' &&
651 strchr(q, ':') != NULL))
652 ismap = true;
653 }
654
655 if (ismap)
656 {
657 /* use entire spec */
658 file = p;
659 }
660 else
661 {
662 file = extrquotstr(p, &q, " ", &ok);
663 if (!ok)
664 {
665 syserr("illegal filename '%s'", p);
666 break;
667 }
668 }
669
670 if (*file == '|' || ismap)
671 p = "%s";
672 else
673 {
674 p = q;
675 if (*p == '\0')
676 p = "%s";
677 else
678 {
679 *p = '\0';
680 while (isascii(*++p) && isspace(*p))
681 continue;
682 }
683 }
684 fileclass(mid, file, p, ismap, safe, optional);
685 break;
686
687 #if XLA
688 case 'L': /* extended load average description */
689 xla_init(&bp[1]);
690 break;
691 #endif
692
693 #if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO)
694 case 'L': /* lookup macro */
695 case 'G': /* lookup class */
696 /* reserved for Sun -- NIS+ database lookup */
697 if (VendorCode != VENDOR_SUN)
698 goto badline;
699 sun_lg_config_line(bp, e);
700 break;
701 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) */
702
703 case 'M': /* define mailer */
704 makemailer(&bp[1]);
705 break;
706
707 case 'O': /* set option */
708 setoption(bp[1], &bp[2], safe, false, e);
709 break;
710
711 case 'P': /* set precedence */
712 if (NumPriorities >= MAXPRIORITIES)
713 {
714 toomany('P', MAXPRIORITIES);
715 break;
716 }
717 for (p = &bp[1]; *p != '\0' && *p != '='; p++)
718 continue;
719 if (*p == '\0')
720 goto badline;
721 *p = '\0';
722 Priorities[NumPriorities].pri_name = newstr(&bp[1]);
723 Priorities[NumPriorities].pri_val = atoi(++p);
724 NumPriorities++;
725 break;
726
727 case 'Q': /* define queue */
728 makequeue(&bp[1], true);
729 break;
730
731 case 'V': /* configuration syntax version */
732 for (p = &bp[1]; SM_ISSPACE(*p); p++)
733 continue;
734 if (!isascii(*p) || !isdigit(*p))
735 {
736 syserr("invalid argument to V line: \"%.20s\"",
737 &bp[1]);
738 break;
739 }
740 ConfigLevel = strtol(p, &ep, 10);
741
742 /*
743 ** Do heuristic tweaking for back compatibility.
744 */
745
746 if (ConfigLevel >= 5)
747 {
748 /* level 5 configs have short name in $w */
749 p = macvalue('w', e);
750 if (p != NULL && (p = strchr(p, '.')) != NULL)
751 {
752 *p = '\0';
753 macdefine(&e->e_macro, A_TEMP, 'w',
754 macvalue('w', e));
755 }
756 }
757 if (ConfigLevel >= 6)
758 {
759 ColonOkInAddr = false;
760 }
761
762 /*
763 ** Look for vendor code.
764 */
765
766 if (*ep++ == '/')
767 {
768 /* extract vendor code */
769 for (p = ep; isascii(*p) && isalpha(*p); )
770 p++;
771 *p = '\0';
772
773 if (!setvendor(ep))
774 syserr("invalid V line vendor code: \"%s\"",
775 ep);
776 }
777 break;
778
779 case 'K':
780 expand(&bp[1], exbuf, sizeof(exbuf), e);
781 (void) makemapentry(exbuf);
782 break;
783
784 case 'E':
785 p = strchr(bp, '=');
786 if (p != NULL)
787 *p++ = '\0';
788 sm_setuserenv(&bp[1], p);
789 break;
790
791 case 'X': /* mail filter */
792 #if MILTER
793 milter_setup(&bp[1]);
794 #else /* MILTER */
795 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
796 "Warning: Filter usage ('X') requires Milter support (-DMILTER)\n");
797 #endif /* MILTER */
798 break;
799
800 default:
801 badline:
802 syserr("unknown configuration line \"%s\"", bp);
803 }
804 if (bp != buf)
805 sm_free(bp); /* XXX */
806 }
807 if (sm_io_error(cf))
808 {
809 syserr("I/O read error");
810 finis(false, true, EX_OSFILE);
811 }
812 (void) sm_io_close(cf, SM_TIME_DEFAULT);
813 FileName = NULL;
814
815 #if _FFR_BOUNCE_QUEUE
816 initbouncequeue();
817 #endif
818
819 /* initialize host maps from local service tables */
820 inithostmaps();
821
822 /* initialize daemon (if not defined yet) */
823 initdaemon();
824
825 /* determine if we need to do special name-server frotz */
826 {
827 int nmaps;
828 char *maptype[MAXMAPSTACK];
829 short mapreturn[MAXMAPACTIONS];
830
831 nmaps = switch_map_find("hosts", maptype, mapreturn);
832 UseNameServer = false;
833 if (nmaps > 0 && nmaps <= MAXMAPSTACK)
834 {
835 register int mapno;
836
837 for (mapno = 0; mapno < nmaps && !UseNameServer;
838 mapno++)
839 {
840 if (strcmp(maptype[mapno], "dns") == 0)
841 UseNameServer = true;
842 }
843 }
844 }
845 setupdynmailers();
846 }
847
848 /*
849 ** TRANSLATE_DOLLARS -- convert $x into internal form
850 **
851 ** Actually does all appropriate pre-processing of a config line
852 ** to turn it into internal form.
853 **
854 ** Parameters:
855 ** ibp -- the buffer to translate.
856 ** obp -- where to put the translation; may be the same as obp
857 ** bsp -- a pointer to the size of obp; will be updated if
858 ** the buffer needs to be replaced.
859 **
860 ** Returns:
861 ** The buffer pointer; may differ from obp if the expansion
862 ** is larger then *bsp, in which case this will point to
863 ** malloc()ed memory which must be free()d by the caller.
864 */
865
866 char *
translate_dollars(ibp,obp,bsp)867 translate_dollars(ibp, obp, bsp)
868 char *ibp;
869 char *obp;
870 int *bsp;
871 {
872 register char *p;
873 auto char *ep;
874 char *bp;
875
876 if (tTd(37, 53))
877 {
878 sm_dprintf("translate_dollars(");
879 xputs(sm_debug_file(), ibp);
880 sm_dprintf(")\n");
881 }
882
883 bp = quote_internal_chars(ibp, obp, bsp, NULL);
884
885 for (p = bp; *p != '\0'; p++)
886 {
887 if (*p == '#' && p > bp && ConfigLevel >= 3)
888 {
889 register char *e;
890
891 switch (*--p & 0377)
892 {
893 case MACROEXPAND:
894 /* it's from $# -- let it go through */
895 p++;
896 break;
897
898 case '\\':
899 /* it's backslash escaped */
900 (void) sm_strlcpy(p, p + 1, strlen(p));
901 break;
902
903 default:
904 /* delete leading white space */
905 while (SM_ISSPACE(*p) &&
906 *p != '\n' && p > bp)
907 {
908 p--;
909 }
910 if ((e = strchr(++p, '\n')) != NULL)
911 (void) sm_strlcpy(p, e, strlen(p));
912 else
913 *p-- = '\0';
914 break;
915 }
916 continue;
917 }
918
919 if (*p != '$' || p[1] == '\0')
920 continue;
921
922 if (p[1] == '$')
923 {
924 /* actual dollar sign.... */
925 (void) sm_strlcpy(p, p + 1, strlen(p));
926 continue;
927 }
928
929 /* convert to macro expansion character */
930 *p++ = MACROEXPAND;
931
932 /* special handling for $=, $~, $&, and $? */
933 if (*p == '=' || *p == '~' || *p == '&' || *p == '?')
934 p++;
935
936 /* convert macro name to code */
937 *p = macid_parse(p, &ep);
938 if (ep != p + 1)
939 (void) sm_strlcpy(p + 1, ep, strlen(p + 1));
940 }
941
942 /* strip trailing white space from the line */
943 while (--p > bp && SM_ISSPACE(*p))
944 *p = '\0';
945
946 if (tTd(37, 53))
947 {
948 sm_dprintf(" translate_dollars => ");
949 xputs(sm_debug_file(), bp);
950 sm_dprintf("\n");
951 }
952
953 return bp;
954 }
955 /*
956 ** TOOMANY -- signal too many of some option
957 **
958 ** Parameters:
959 ** id -- the id of the error line
960 ** maxcnt -- the maximum possible values
961 **
962 ** Returns:
963 ** none.
964 **
965 ** Side Effects:
966 ** gives a syserr.
967 */
968
969 static void
toomany(id,maxcnt)970 toomany(id, maxcnt)
971 int id;
972 int maxcnt;
973 {
974 syserr("too many %c lines, %d max", id, maxcnt);
975 }
976 /*
977 ** FILECLASS -- read members of a class from a file, program, or map
978 **
979 ** Parameters:
980 ** class -- class to define.
981 ** filename -- name of file to read/specification of map and key.
982 ** fmt -- scanf string to use for match.
983 ** ismap -- if set, this is a map lookup.
984 ** safe -- if set, this is a safe read.
985 ** optional -- if set, it is not an error for the file to
986 ** not exist.
987 **
988 ** Returns:
989 ** none
990 **
991 ** Side Effects:
992 ** puts all entries retrieved from a file, program, or map
993 ** into the named class:
994 ** - file or |prg: all words in lines that match a scanf fmt
995 ** - map: all words in value (rhs) of a map lookup of a key
996 */
997
998 /*
999 ** Break up the match into words and add to class.
1000 */
1001
1002 static void
parse_class_words(class,line)1003 parse_class_words(class, line)
1004 int class;
1005 char *line;
1006 {
1007 while (line != NULL && *line != '\0')
1008 {
1009 register char *q;
1010
1011 /* strip leading spaces */
1012 while (SM_ISSPACE(*line))
1013 line++;
1014 if (*line == '\0')
1015 break;
1016
1017 /* find the end of the word */
1018 q = line;
1019 while (*line != '\0' && !(SM_ISSPACE(*line)))
1020 line++;
1021 if (*line != '\0')
1022 *line++ = '\0';
1023
1024 /* enter the word in the symbol table */
1025 setclass(class, q);
1026 }
1027 }
1028
1029 static void
fileclass(class,filename,fmt,ismap,safe,optional)1030 fileclass(class, filename, fmt, ismap, safe, optional)
1031 int class;
1032 char *filename;
1033 char *fmt;
1034 bool ismap;
1035 bool safe;
1036 bool optional;
1037 {
1038 SM_FILE_T *f;
1039 long sff;
1040 pid_t pid;
1041 register char *p;
1042 char buf[MAXLINE];
1043
1044 if (tTd(37, 2))
1045 sm_dprintf("fileclass(%s, fmt=%s)\n", filename, fmt);
1046
1047 if (*filename == '\0')
1048 {
1049 syserr("fileclass: missing file name");
1050 return;
1051 }
1052 else if (ismap)
1053 {
1054 int status = 0;
1055 char *key;
1056 char *mn;
1057 char *cl, *spec;
1058 STAB *mapclass;
1059 MAP map;
1060
1061 mn = newstr(macname(class));
1062
1063 key = filename;
1064
1065 /* skip past key */
1066 if ((p = strchr(filename, '@')) == NULL)
1067 {
1068 /* should not happen */
1069 syserr("fileclass: bogus map specification");
1070 sm_free(mn);
1071 return;
1072 }
1073
1074 /* skip past '@' */
1075 *p++ = '\0';
1076 cl = p;
1077
1078 #if LDAPMAP
1079 if (strcmp(cl, "LDAP") == 0)
1080 {
1081 int n;
1082 char *lc;
1083 char jbuf[MAXHOSTNAMELEN];
1084 char lcbuf[MAXLINE];
1085
1086 /* Get $j */
1087 expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope);
1088 if (jbuf[0] == '\0')
1089 {
1090 (void) sm_strlcpy(jbuf, "localhost",
1091 sizeof(jbuf));
1092 }
1093
1094 /* impose the default schema */
1095 lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
1096 if (lc == NULL)
1097 lc = "";
1098 else
1099 {
1100 expand(lc, lcbuf, sizeof(lcbuf), CurEnv);
1101 lc = lcbuf;
1102 }
1103
1104 cl = "ldap";
1105 n = sm_snprintf(buf, sizeof(buf),
1106 "-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName=%s)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))) -v sendmailMTAClassValue,sendmailMTAClassSearch:FILTER:sendmailMTAClass,sendmailMTAClassURL:URL:sendmailMTAClass",
1107 mn, lc, jbuf);
1108 if (n >= sizeof(buf))
1109 {
1110 syserr("fileclass: F{%s}: Default LDAP string too long",
1111 mn);
1112 sm_free(mn);
1113 return;
1114 }
1115 spec = buf;
1116 }
1117 else
1118 #endif /* LDAPMAP */
1119 {
1120 if ((spec = strchr(cl, ':')) == NULL)
1121 {
1122 syserr("fileclass: F{%s}: missing map class",
1123 mn);
1124 sm_free(mn);
1125 return;
1126 }
1127 *spec++ ='\0';
1128 }
1129
1130 /* set up map structure */
1131 mapclass = stab(cl, ST_MAPCLASS, ST_FIND);
1132 if (mapclass == NULL)
1133 {
1134 syserr("fileclass: F{%s}: class %s not available",
1135 mn, cl);
1136 sm_free(mn);
1137 return;
1138 }
1139 memset(&map, '\0', sizeof(map));
1140 map.map_class = &mapclass->s_mapclass;
1141 map.map_mname = mn;
1142 map.map_mflags |= MF_FILECLASS;
1143
1144 if (tTd(37, 5))
1145 sm_dprintf("fileclass: F{%s}: map class %s, key %s, spec %s\n",
1146 mn, cl, key, spec);
1147
1148 /* parse map spec */
1149 if (!map.map_class->map_parse(&map, spec))
1150 {
1151 /* map_parse() showed the error already */
1152 sm_free(mn);
1153 return;
1154 }
1155 map.map_mflags |= MF_VALID;
1156
1157 /* open map */
1158 if (map.map_class->map_open(&map, O_RDONLY))
1159 {
1160 map.map_mflags |= MF_OPEN;
1161 map.map_pid = getpid();
1162 }
1163 else
1164 {
1165 if (!optional &&
1166 !bitset(MF_OPTIONAL, map.map_mflags))
1167 syserr("fileclass: F{%s}: map open failed",
1168 mn);
1169 sm_free(mn);
1170 return;
1171 }
1172
1173 /* lookup */
1174 p = (*map.map_class->map_lookup)(&map, key, NULL, &status);
1175 if (status != EX_OK && status != EX_NOTFOUND)
1176 {
1177 if (!optional)
1178 syserr("fileclass: F{%s}: map lookup failed",
1179 mn);
1180 p = NULL;
1181 }
1182
1183 /* use the results */
1184 if (p != NULL)
1185 parse_class_words(class, p);
1186
1187 /* close map */
1188 map.map_mflags |= MF_CLOSING;
1189 map.map_class->map_close(&map);
1190 map.map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
1191 sm_free(mn);
1192 return;
1193 }
1194 else if (filename[0] == '|')
1195 {
1196 auto int fd;
1197 int i;
1198 char *argv[MAXPV + 1];
1199
1200 i = 0;
1201 for (p = strtok(&filename[1], " \t");
1202 p != NULL && i < MAXPV;
1203 p = strtok(NULL, " \t"))
1204 argv[i++] = p;
1205 argv[i] = NULL;
1206 pid = prog_open(argv, &fd, CurEnv);
1207 if (pid < 0)
1208 f = NULL;
1209 else
1210 f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
1211 (void *) &fd, SM_IO_RDONLY, NULL);
1212 }
1213 else
1214 {
1215 pid = -1;
1216 sff = SFF_REGONLY;
1217 if (!bitnset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail))
1218 sff |= SFF_SAFEDIRPATH;
1219 if (!bitnset(DBS_LINKEDCLASSFILEINWRITABLEDIR,
1220 DontBlameSendmail))
1221 sff |= SFF_NOWLINK;
1222 if (safe)
1223 sff |= SFF_OPENASROOT;
1224 else if (RealUid == 0)
1225 sff |= SFF_ROOTOK;
1226 if (DontLockReadFiles)
1227 sff |= SFF_NOLOCK;
1228 f = safefopen(filename, O_RDONLY, 0, sff);
1229 }
1230 if (f == NULL)
1231 {
1232 if (!optional)
1233 syserr("fileclass: cannot open '%s'", filename);
1234 return;
1235 }
1236
1237 while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
1238 {
1239 #if SCANF
1240 char wordbuf[MAXLINE + 1];
1241 #endif
1242
1243 if (buf[0] == '#')
1244 continue;
1245 #if SCANF
1246 if (sm_io_sscanf(buf, fmt, wordbuf) != 1)
1247 continue;
1248 p = wordbuf;
1249 #else /* SCANF */
1250 p = buf;
1251 #endif /* SCANF */
1252
1253 parse_class_words(class, p);
1254
1255 /*
1256 ** If anything else is added here,
1257 ** check if the '@' map case above
1258 ** needs the code as well.
1259 */
1260 }
1261
1262 (void) sm_io_close(f, SM_TIME_DEFAULT);
1263 if (pid > 0)
1264 (void) waitfor(pid);
1265 }
1266
1267 #if _FFR_DYN_CLASS
1268
1269 /*
1270 ** DYNCLASS -- open a dynamic class
1271 **
1272 ** Parameters:
1273 ** class -- class to define.
1274 ** arg -- rest of class definition from cf.
1275 **
1276 ** Returns:
1277 ** none
1278 */
1279
1280 static void
dynclass(class,arg)1281 dynclass(class, arg)
1282 int class;
1283 char *arg;
1284 {
1285 char *p;
1286 char *tag;
1287 char *mn;
1288 char *maptype, *spec;
1289 STAB *mapclass, *dynmap;
1290
1291 mn = newstr(macname(class));
1292 if (*arg == '\0')
1293 {
1294 syserr("dynamic class: A{%s}: missing class definition", mn);
1295 return;
1296 }
1297 tag = arg;
1298 dynmap = stab(mn, ST_DYNMAP, ST_FIND);
1299 if (NULL != dynmap)
1300 {
1301 syserr("dynamic class: A{%s}: already defined", mn);
1302 goto error;
1303 }
1304
1305 /* skip past tag */
1306 if ((p = strchr(arg, '@')) == NULL)
1307 {
1308 /* should not happen */
1309 syserr("dynamic class: A{%s}: bogus map specification", mn);
1310 goto error;
1311 }
1312
1313 /* skip past '@' */
1314 *p++ = '\0';
1315 maptype = p;
1316
1317 if ((spec = strchr(maptype, ':')) == NULL)
1318 {
1319 syserr("dynamic class: A{%s}: missing map class", mn);
1320 goto error;
1321 }
1322 *spec++ ='\0';
1323
1324 /* set up map structure */
1325 mapclass = stab(maptype, ST_MAPCLASS, ST_FIND);
1326 if (NULL == mapclass)
1327 {
1328 syserr("dynamic class: A{%s}: map type %s not available",
1329 mn, maptype);
1330 goto error;
1331 }
1332
1333 if (tTd(37, 5))
1334 sm_dprintf("dynamic class: A{%s}: type='%s', tag='%s', spec='%s'\n",
1335 mn, maptype, tag, spec);
1336
1337 /* enter map in stab */
1338 dynmap = stab(mn, ST_DYNMAP, ST_ENTER);
1339 if (NULL == dynmap)
1340 {
1341 syserr("dynamic class: A{%s}: cannot enter", mn);
1342 goto error2;
1343 }
1344 dynmap->s_dynclass.map_class = &mapclass->s_mapclass;
1345 dynmap->s_dynclass.map_mname = newstr(mn);
1346
1347 /* parse map spec */
1348 if (!dynmap->s_dynclass.map_class->map_parse(&dynmap->s_dynclass, spec))
1349 {
1350 /* map_parse() showed the error already */
1351 goto error;
1352 }
1353
1354 /* open map */
1355 if (dynmap->s_dynclass.map_class->map_open(&dynmap->s_dynclass, O_RDONLY))
1356 {
1357 dynmap->s_dynclass.map_mflags |= MF_OPEN;
1358 dynmap->s_dynclass.map_pid = getpid();
1359 }
1360 else
1361 {
1362 syserr("dynamic class: A{%s}: map open failed", mn);
1363 goto error;
1364 }
1365 dynmap->s_dynclass.map_mflags |= MF_VALID;
1366 dynmap->s_dynclass.map_tag = newstr(tag);
1367
1368 #if 0
1369 /* close map: where to do this? */
1370 dynmap->s_dynclass.map_mflags |= MF_CLOSING;
1371 dynmap->s_dynclass.map_class->map_close(&map);
1372 dynmap->s_dynclass.map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
1373 #endif
1374 sm_free(mn);
1375 return;
1376
1377 error:
1378 dynmap->s_dynclass.map_mflags |= MF_OPENBOGUS;
1379 error2:
1380 sm_free(mn);
1381 return;
1382 }
1383 #endif
1384
1385 #if _FFR_RCPTFLAGS
1386 /* first character for dynamically created mailers */
1387 static char dynmailerp = ' ';
1388
1389 /* list of first characters for cf defined mailers */
1390 static char frst[MAXMAILERS + 1];
1391
1392 /*
1393 ** SETUPDYNMAILERS -- find a char that isn't used as first element of any
1394 ** mailer name.
1395 **
1396 ** Parameters:
1397 ** none
1398 **
1399 ** Returns:
1400 ** none
1401 **
1402 ** Note: space is not valid in cf defined mailers hence the function
1403 ** will always find a char. It's not nice, but this is for
1404 ** internal names only.
1405 */
1406
1407 void
setupdynmailers()1408 setupdynmailers()
1409 {
1410 int i;
1411 char pp[] = "YXZ0123456789ABCDEFGHIJKLMNOPQRSTUVWyxzabcfghijkmnoqtuvw ";
1412
1413 frst[MAXMAILERS] = '\0';
1414 for (i = 0; i < strlen(pp); i++)
1415 {
1416 if (strchr(frst, pp[i]) == NULL)
1417 {
1418 dynmailerp = pp[i];
1419 if (tTd(25, 8))
1420 sm_dprintf("dynmailerp=%c\n", dynmailerp);
1421 return;
1422 }
1423 }
1424
1425 /* NOTREACHED */
1426 SM_ASSERT(0);
1427 }
1428
1429 /*
1430 ** NEWMODMAILER -- Create a new mailer with modifications
1431 **
1432 ** Parameters:
1433 ** rcpt -- current RCPT
1434 ** fl -- flag to set
1435 **
1436 ** Returns:
1437 ** true iff successful.
1438 **
1439 ** Note: this creates a copy of the mailer for the rcpt and
1440 ** modifies exactly one flag. It does not work
1441 ** for multiple flags!
1442 */
1443
1444 bool
newmodmailer(rcpt,fl)1445 newmodmailer(rcpt, fl)
1446 ADDRESS *rcpt;
1447 int fl;
1448 {
1449 int idx;
1450 struct mailer *m;
1451 STAB *s;
1452 char mname[256];
1453
1454 SM_REQUIRE(rcpt != NULL);
1455 if (rcpt->q_mailer == NULL)
1456 return false;
1457 if (tTd(25, 8))
1458 sm_dprintf("newmodmailer: rcpt=%s\n", rcpt->q_paddr);
1459 SM_REQUIRE(rcpt->q_mailer->m_name != NULL);
1460 SM_REQUIRE(rcpt->q_mailer->m_name[0] != '\0');
1461 sm_strlcpy(mname, rcpt->q_mailer->m_name, sizeof(mname));
1462 mname[0] = dynmailerp;
1463 if (tTd(25, 8))
1464 sm_dprintf("newmodmailer: name=%s\n", mname);
1465 s = stab(mname, ST_MAILER, ST_ENTER);
1466 if (s->s_mailer != NULL)
1467 {
1468 idx = s->s_mailer->m_mno;
1469 if (tTd(25, 6))
1470 sm_dprintf("newmodmailer: found idx=%d\n", idx);
1471 }
1472 else
1473 {
1474 idx = rcpt->q_mailer->m_mno;
1475 idx += MAXMAILERS;
1476 if (tTd(25, 6))
1477 sm_dprintf("newmodmailer: idx=%d\n", idx);
1478 if (idx > SM_ARRAY_SIZE(Mailer))
1479 return false;
1480 }
1481
1482 m = Mailer[idx];
1483 if (m == NULL)
1484 m = (struct mailer *) xalloc(sizeof(*m));
1485 memset((char *) m, '\0', sizeof(*m));
1486 STRUCTCOPY(*rcpt->q_mailer, *m);
1487 Mailer[idx] = m;
1488
1489 /* "modify" the mailer */
1490 setbitn(bitidx(fl), m->m_flags);
1491 rcpt->q_mailer = m;
1492 m->m_mno = idx;
1493 m->m_name = newstr(mname);
1494 if (tTd(25, 1))
1495 sm_dprintf("newmodmailer: mailer[%d]=%s %p\n",
1496 idx, Mailer[idx]->m_name, Mailer[idx]);
1497
1498 return true;
1499 }
1500
1501 #endif /* _FFR_RCPTFLAGS */
1502
1503 /*
1504 ** MAKEMAILER -- define a new mailer.
1505 **
1506 ** Parameters:
1507 ** line -- description of mailer. This is in labeled
1508 ** fields. The fields are:
1509 ** A -- the argv for this mailer
1510 ** C -- the character set for MIME conversions
1511 ** D -- the directory to run in
1512 ** E -- the eol string
1513 ** F -- the flags associated with the mailer
1514 ** L -- the maximum line length
1515 ** M -- the maximum message size
1516 ** N -- the niceness at which to run
1517 ** P -- the path to the mailer
1518 ** Q -- the queue group for the mailer
1519 ** R -- the recipient rewriting set
1520 ** S -- the sender rewriting set
1521 ** T -- the mailer type (for DSNs)
1522 ** U -- the uid to run as
1523 ** W -- the time to wait at the end
1524 ** m -- maximum messages per connection
1525 ** r -- maximum number of recipients per message
1526 ** / -- new root directory
1527 ** The first word is the canonical name of the mailer.
1528 **
1529 ** Returns:
1530 ** none.
1531 **
1532 ** Side Effects:
1533 ** enters the mailer into the mailer table.
1534 */
1535
1536 void
makemailer(line)1537 makemailer(line)
1538 char *line;
1539 {
1540 register char *p;
1541 register struct mailer *m;
1542 register STAB *s;
1543 int i;
1544 char fcode;
1545 auto char *endp;
1546 static int nextmailer = 0; /* "free" index into Mailer struct */
1547
1548 /* allocate a mailer and set up defaults */
1549 m = (struct mailer *) sm_malloc_tagged_x(sizeof(*m), "mailer", 0, 0);
1550 memset((char *) m, '\0', sizeof(*m));
1551 errno = 0; /* avoid bogus error text */
1552
1553 /* collect the mailer name */
1554 for (p = line;
1555 *p != '\0' && *p != ',' && !(SM_ISSPACE(*p));
1556 p++)
1557 continue;
1558 if (*p != '\0')
1559 *p++ = '\0';
1560 if (line[0] == '\0')
1561 {
1562 syserr("name required for mailer");
1563 return;
1564 }
1565 m->m_name = newstr(line);
1566 #if _FFR_RCPTFLAGS
1567 frst[nextmailer] = line[0];
1568 #endif
1569 m->m_qgrp = NOQGRP;
1570 m->m_uid = NO_UID;
1571 m->m_gid = NO_GID;
1572
1573 /* now scan through and assign info from the fields */
1574 while (*p != '\0')
1575 {
1576 auto char *delimptr;
1577
1578 while (*p != '\0' &&
1579 (*p == ',' || (SM_ISSPACE(*p))))
1580 p++;
1581
1582 /* p now points to field code */
1583 fcode = *p;
1584 while (*p != '\0' && *p != '=' && *p != ',')
1585 p++;
1586 if (*p++ != '=')
1587 {
1588 syserr("mailer %s: `=' expected", m->m_name);
1589 return;
1590 }
1591 while (SM_ISSPACE(*p))
1592 p++;
1593
1594 /* p now points to the field body */
1595 p = munchstring(p, &delimptr, ',');
1596
1597 /* install the field into the mailer struct */
1598 switch (fcode)
1599 {
1600 case 'P': /* pathname */
1601 if (*p != '\0') /* error is issued below */
1602 m->m_mailer = newstr(p);
1603 break;
1604
1605 case 'F': /* flags */
1606 for (; *p != '\0'; p++)
1607 {
1608 if (!(SM_ISSPACE(*p)))
1609 {
1610 if (*p == M_INTERNAL)
1611 sm_syslog(LOG_WARNING, NOQID,
1612 "WARNING: mailer=%s, flag=%c deprecated",
1613 m->m_name, *p);
1614 setbitn(bitidx(*p), m->m_flags);
1615 }
1616 }
1617 break;
1618
1619 case 'S': /* sender rewriting ruleset */
1620 case 'R': /* recipient rewriting ruleset */
1621 i = strtorwset(p, &endp, ST_ENTER);
1622 if (i < 0)
1623 return;
1624 if (fcode == 'S')
1625 m->m_sh_rwset = m->m_se_rwset = i;
1626 else
1627 m->m_rh_rwset = m->m_re_rwset = i;
1628
1629 p = endp;
1630 if (*p++ == '/')
1631 {
1632 i = strtorwset(p, NULL, ST_ENTER);
1633 if (i < 0)
1634 return;
1635 if (fcode == 'S')
1636 m->m_sh_rwset = i;
1637 else
1638 m->m_rh_rwset = i;
1639 }
1640 break;
1641
1642 case 'E': /* end of line string */
1643 if (*p == '\0')
1644 syserr("mailer %s: null end-of-line string",
1645 m->m_name);
1646 else
1647 m->m_eol = newstr(p);
1648 break;
1649
1650 case 'A': /* argument vector */
1651 if (*p != '\0') /* error is issued below */
1652 m->m_argv = makeargv(p);
1653 break;
1654
1655 case 'M': /* maximum message size */
1656 m->m_maxsize = atol(p);
1657 break;
1658
1659 case 'm': /* maximum messages per connection */
1660 m->m_maxdeliveries = atoi(p);
1661 break;
1662
1663 case 'r': /* max recipient per envelope */
1664 m->m_maxrcpt = atoi(p);
1665 break;
1666
1667 case 'L': /* maximum line length */
1668 m->m_linelimit = atoi(p);
1669 if (m->m_linelimit < 0)
1670 m->m_linelimit = 0;
1671 break;
1672
1673 case 'N': /* run niceness */
1674 m->m_nice = atoi(p);
1675 break;
1676
1677 case 'D': /* working directory */
1678 if (*p == '\0')
1679 syserr("mailer %s: null working directory",
1680 m->m_name);
1681 else
1682 m->m_execdir = newstr(p);
1683 break;
1684
1685 case 'C': /* default charset */
1686 if (*p == '\0')
1687 syserr("mailer %s: null charset", m->m_name);
1688 else
1689 m->m_defcharset = newstr(p);
1690 break;
1691
1692 case 'Q': /* queue for this mailer */
1693 if (*p == '\0')
1694 {
1695 syserr("mailer %s: null queue", m->m_name);
1696 break;
1697 }
1698 s = stab(p, ST_QUEUE, ST_FIND);
1699 if (s == NULL)
1700 syserr("mailer %s: unknown queue %s",
1701 m->m_name, p);
1702 else
1703 m->m_qgrp = s->s_quegrp->qg_index;
1704 break;
1705
1706 case 'T': /* MTA-Name/Address/Diagnostic types */
1707 /* extract MTA name type; default to "dns" */
1708 m->m_mtatype = newstr(p);
1709 p = strchr(m->m_mtatype, '/');
1710 if (p != NULL)
1711 {
1712 *p++ = '\0';
1713 if (*p == '\0')
1714 p = NULL;
1715 }
1716 if (*m->m_mtatype == '\0')
1717 m->m_mtatype = "dns";
1718
1719 /* extract address type; default to "rfc822" */
1720 m->m_addrtype = p;
1721 if (p != NULL)
1722 p = strchr(p, '/');
1723 if (p != NULL)
1724 {
1725 *p++ = '\0';
1726 if (*p == '\0')
1727 p = NULL;
1728 }
1729 if (SM_IS_EMPTY(m->m_addrtype))
1730 m->m_addrtype = "rfc822";
1731
1732 /* extract diagnostic type; default to "smtp" */
1733 m->m_diagtype = p;
1734 if (SM_IS_EMPTY(m->m_diagtype))
1735 m->m_diagtype = "smtp";
1736 break;
1737
1738 case 'U': /* user id */
1739 if (isascii(*p) && !isdigit(*p))
1740 {
1741 char *q = p;
1742 struct passwd *pw;
1743
1744 while (*p != '\0' && isascii(*p) &&
1745 #if _FFR_DOTTED_USERNAMES
1746 (isalnum(*p) || strchr(SM_PWN_CHARS, *p) != NULL))
1747 #else
1748 (isalnum(*p) || strchr("-_", *p) != NULL))
1749 #endif
1750 p++;
1751 while (SM_ISSPACE(*p))
1752 *p++ = '\0';
1753 if (*p != '\0')
1754 *p++ = '\0';
1755 if (*q == '\0')
1756 {
1757 syserr("mailer %s: null user name",
1758 m->m_name);
1759 break;
1760 }
1761 pw = sm_getpwnam(q);
1762 if (pw == NULL)
1763 {
1764 syserr("readcf: mailer U= flag: unknown user %s", q);
1765 break;
1766 }
1767 else
1768 {
1769 m->m_uid = pw->pw_uid;
1770 m->m_gid = pw->pw_gid;
1771 }
1772 }
1773 else
1774 {
1775 auto char *q;
1776
1777 m->m_uid = strtol(p, &q, 0);
1778 p = q;
1779 while (SM_ISSPACE(*p))
1780 p++;
1781 if (*p != '\0')
1782 p++;
1783 }
1784 while (SM_ISSPACE(*p))
1785 p++;
1786 if (*p == '\0')
1787 break;
1788 if (isascii(*p) && !isdigit(*p))
1789 {
1790 char *q = p;
1791 struct group *gr;
1792
1793 while (isascii(*p) &&
1794 (isalnum(*p) || strchr(SM_PWN_CHARS, *p) != NULL))
1795 p++;
1796 *p++ = '\0';
1797 if (*q == '\0')
1798 {
1799 syserr("mailer %s: null group name",
1800 m->m_name);
1801 break;
1802 }
1803 gr = getgrnam(q);
1804 if (gr == NULL)
1805 {
1806 syserr("readcf: mailer U= flag: unknown group %s", q);
1807 break;
1808 }
1809 else
1810 m->m_gid = gr->gr_gid;
1811 }
1812 else
1813 {
1814 m->m_gid = strtol(p, NULL, 0);
1815 }
1816 break;
1817
1818 case 'W': /* wait timeout */
1819 m->m_wait = convtime(p, 's');
1820 break;
1821
1822 case '/': /* new root directory */
1823 if (*p == '\0')
1824 syserr("mailer %s: null root directory",
1825 m->m_name);
1826 else
1827 m->m_rootdir = newstr(p);
1828 break;
1829
1830 default:
1831 syserr("M%s: unknown mailer equate %c=",
1832 m->m_name, fcode);
1833 break;
1834 }
1835
1836 p = delimptr;
1837 }
1838
1839 #if !HASRRESVPORT
1840 if (bitnset(M_SECURE_PORT, m->m_flags))
1841 {
1842 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1843 "M%s: Warning: F=%c set on system that doesn't support rresvport()\n",
1844 m->m_name, M_SECURE_PORT);
1845 }
1846 #endif /* !HASRRESVPORT */
1847
1848 #if !HASNICE
1849 if (m->m_nice != 0)
1850 {
1851 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1852 "M%s: Warning: N= set on system that doesn't support nice()\n",
1853 m->m_name);
1854 }
1855 #endif /* !HASNICE */
1856
1857 /* do some rationality checking */
1858 if (m->m_argv == NULL)
1859 {
1860 syserr("M%s: A= argument required", m->m_name);
1861 return;
1862 }
1863 if (m->m_mailer == NULL)
1864 {
1865 syserr("M%s: P= argument required", m->m_name);
1866 return;
1867 }
1868
1869 if (nextmailer >= MAXMAILERS)
1870 {
1871 syserr("too many mailers defined (%d max)", MAXMAILERS);
1872 return;
1873 }
1874
1875 if (m->m_maxrcpt <= 0)
1876 m->m_maxrcpt = DEFAULT_MAX_RCPT;
1877
1878 /* do some heuristic cleanup for back compatibility */
1879 if (bitnset(M_LIMITS, m->m_flags))
1880 {
1881 if (m->m_linelimit == 0)
1882 m->m_linelimit = SMTPLINELIM;
1883 if (ConfigLevel < 2)
1884 setbitn(M_7BITS, m->m_flags);
1885 }
1886
1887 if (strcmp(m->m_mailer, "[TCP]") == 0)
1888 {
1889 syserr("M%s: P=[TCP] must be replaced by P=[IPC]", m->m_name);
1890 return;
1891 }
1892
1893 if (strcmp(m->m_mailer, "[IPC]") == 0)
1894 {
1895 /* Use the second argument for host or path to socket */
1896 if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
1897 m->m_argv[1][0] == '\0')
1898 {
1899 syserr("M%s: too few parameters for %s mailer",
1900 m->m_name, m->m_mailer);
1901 return;
1902 }
1903 if (strcmp(m->m_argv[0], "TCP") != 0
1904 #if NETUNIX
1905 && strcmp(m->m_argv[0], "FILE") != 0
1906 #endif
1907 )
1908 {
1909 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1910 "M%s: Warning: first argument in %s mailer must be %s\n",
1911 m->m_name, m->m_mailer,
1912 #if NETUNIX
1913 "TCP or FILE"
1914 #else
1915 "TCP"
1916 #endif
1917 );
1918 }
1919 if (m->m_mtatype == NULL)
1920 m->m_mtatype = "dns";
1921 if (m->m_addrtype == NULL)
1922 m->m_addrtype = "rfc822";
1923 if (m->m_diagtype == NULL)
1924 {
1925 if (m->m_argv[0] != NULL &&
1926 strcmp(m->m_argv[0], "FILE") == 0)
1927 m->m_diagtype = "x-unix";
1928 else
1929 m->m_diagtype = "smtp";
1930 }
1931 }
1932 else if (strcmp(m->m_mailer, "[FILE]") == 0)
1933 {
1934 /* Use the second argument for filename */
1935 if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
1936 m->m_argv[2] != NULL)
1937 {
1938 syserr("M%s: too %s parameters for [FILE] mailer",
1939 m->m_name,
1940 (m->m_argv[0] == NULL ||
1941 m->m_argv[1] == NULL) ? "few" : "many");
1942 return;
1943 }
1944 else if (strcmp(m->m_argv[0], "FILE") != 0)
1945 {
1946 syserr("M%s: first argument in [FILE] mailer must be FILE",
1947 m->m_name);
1948 return;
1949 }
1950 }
1951
1952 if (m->m_eol == NULL)
1953 {
1954 char **pp;
1955
1956 /* default for SMTP is \r\n; use \n for local delivery */
1957 for (pp = m->m_argv; *pp != NULL; pp++)
1958 {
1959 for (p = *pp; *p != '\0'; )
1960 {
1961 if ((*p++ & 0377) == MACROEXPAND && *p == 'u')
1962 break;
1963 }
1964 if (*p != '\0')
1965 break;
1966 }
1967 if (*pp == NULL)
1968 m->m_eol = "\r\n";
1969 else
1970 m->m_eol = "\n";
1971 }
1972
1973 /* enter the mailer into the symbol table */
1974 s = stab(m->m_name, ST_MAILER, ST_ENTER);
1975 if (s->s_mailer != NULL)
1976 {
1977 i = s->s_mailer->m_mno;
1978 sm_free(s->s_mailer); /* XXX */
1979 }
1980 else
1981 {
1982 i = nextmailer++;
1983 }
1984 Mailer[i] = s->s_mailer = m;
1985 m->m_mno = i;
1986 }
1987 /*
1988 ** MUNCHSTRING -- translate a string into internal form.
1989 **
1990 ** Parameters:
1991 ** p -- the string to munch.
1992 ** delimptr -- if non-NULL, set to the pointer of the
1993 ** field delimiter character.
1994 ** delim -- the delimiter for the field.
1995 **
1996 ** Returns:
1997 ** the munched string.
1998 **
1999 ** Side Effects:
2000 ** the munched string is a local static buffer.
2001 ** it must be copied before the function is called again.
2002 */
2003
2004 char *
munchstring(p,delimptr,delim)2005 munchstring(p, delimptr, delim)
2006 register char *p;
2007 char **delimptr;
2008 int delim;
2009 {
2010 register char *q;
2011 bool backslash = false;
2012 bool quotemode = false;
2013 static char buf[MAXLINE];
2014
2015 for (q = buf; *p != '\0' && q < &buf[sizeof(buf) - 1]; p++)
2016 {
2017 if (backslash)
2018 {
2019 /* everything is roughly literal */
2020 backslash = false;
2021 switch (*p)
2022 {
2023 case 'r': /* carriage return */
2024 *q++ = '\r';
2025 continue;
2026
2027 case 'n': /* newline */
2028 *q++ = '\n';
2029 continue;
2030
2031 case 'f': /* form feed */
2032 *q++ = '\f';
2033 continue;
2034
2035 case 'b': /* backspace */
2036 *q++ = '\b';
2037 continue;
2038 }
2039 *q++ = *p;
2040 }
2041 else
2042 {
2043 if (*p == '\\')
2044 backslash = true;
2045 else if (*p == '"')
2046 quotemode = !quotemode;
2047 else if (quotemode || *p != delim)
2048 *q++ = *p;
2049 else
2050 break;
2051 }
2052 }
2053
2054 if (delimptr != NULL)
2055 *delimptr = p;
2056 *q++ = '\0';
2057 return buf;
2058 }
2059 /*
2060 ** EXTRQUOTSTR -- extract a (quoted) string.
2061 **
2062 ** This routine deals with quoted (") strings and escaped
2063 ** spaces (\\ ).
2064 **
2065 ** Parameters:
2066 ** p -- source string.
2067 ** delimptr -- if non-NULL, set to the pointer of the
2068 ** field delimiter character.
2069 ** delimbuf -- delimiters for the field.
2070 ** st -- if non-NULL, store the return value (whether the
2071 ** string was correctly quoted) here.
2072 **
2073 ** Returns:
2074 ** the extracted string.
2075 **
2076 ** Side Effects:
2077 ** the returned string is a local static buffer.
2078 ** it must be copied before the function is called again.
2079 */
2080
2081 static char *
extrquotstr(p,delimptr,delimbuf,st)2082 extrquotstr(p, delimptr, delimbuf, st)
2083 register char *p;
2084 char **delimptr;
2085 char *delimbuf;
2086 bool *st;
2087 {
2088 register char *q;
2089 bool backslash = false;
2090 bool quotemode = false;
2091 static char buf[MAXLINE];
2092
2093 for (q = buf; *p != '\0' && q < &buf[sizeof(buf) - 1]; p++)
2094 {
2095 if (backslash)
2096 {
2097 backslash = false;
2098 if (*p != ' ')
2099 *q++ = '\\';
2100 }
2101 if (*p == '\\')
2102 backslash = true;
2103 else if (*p == '"')
2104 quotemode = !quotemode;
2105 else if (quotemode ||
2106 strchr(delimbuf, (int) *p) == NULL)
2107 *q++ = *p;
2108 else
2109 break;
2110 }
2111
2112 if (delimptr != NULL)
2113 *delimptr = p;
2114 *q++ = '\0';
2115 if (st != NULL)
2116 *st = !(quotemode || backslash);
2117 return buf;
2118 }
2119 /*
2120 ** MAKEARGV -- break up a string into words
2121 **
2122 ** Parameters:
2123 ** p -- the string to break up.
2124 **
2125 ** Returns:
2126 ** a char **argv (dynamically allocated)
2127 **
2128 ** Side Effects:
2129 ** munges p.
2130 */
2131
2132 static char **
makeargv(p)2133 makeargv(p)
2134 register char *p;
2135 {
2136 char *q;
2137 int i;
2138 char **avp;
2139 char *argv[MAXPV + 1];
2140
2141 /* take apart the words */
2142 i = 0;
2143 while (*p != '\0' && i < MAXPV)
2144 {
2145 q = p;
2146 while (*p != '\0' && !(SM_ISSPACE(*p)))
2147 p++;
2148 while (SM_ISSPACE(*p))
2149 *p++ = '\0';
2150 argv[i++] = newstr(q);
2151 }
2152 argv[i++] = NULL;
2153
2154 /* now make a copy of the argv */
2155 avp = (char **) sm_malloc_tagged_x(sizeof(*avp) * i, "makeargv", 0, 0);
2156 memmove((char *) avp, (char *) argv, sizeof(*avp) * i);
2157
2158 return avp;
2159 }
2160 /*
2161 ** PRINTRULES -- print rewrite rules (for debugging)
2162 **
2163 ** Parameters:
2164 ** none.
2165 **
2166 ** Returns:
2167 ** none.
2168 **
2169 ** Side Effects:
2170 ** prints rewrite rules.
2171 */
2172
2173 void
printrules()2174 printrules()
2175 {
2176 register struct rewrite *rwp;
2177 register int ruleset;
2178
2179 for (ruleset = 0; ruleset < 10; ruleset++)
2180 {
2181 if (RewriteRules[ruleset] == NULL)
2182 continue;
2183 sm_dprintf("\n----Rule Set %d:", ruleset);
2184
2185 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
2186 {
2187 sm_dprintf("\nLHS:");
2188 printav(sm_debug_file(), rwp->r_lhs);
2189 sm_dprintf("RHS:");
2190 printav(sm_debug_file(), rwp->r_rhs);
2191 }
2192 }
2193 }
2194 /*
2195 ** PRINTMAILER -- print mailer structure (for debugging)
2196 **
2197 ** Parameters:
2198 ** fp -- output file
2199 ** m -- the mailer to print
2200 **
2201 ** Returns:
2202 ** none.
2203 */
2204
2205 void
printmailer(fp,m)2206 printmailer(fp, m)
2207 SM_FILE_T *fp;
2208 register MAILER *m;
2209 {
2210 int j;
2211
2212 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2213 "mailer %d (%s): P=%s S=", m->m_mno, m->m_name,
2214 m->m_mailer);
2215 if (RuleSetNames[m->m_se_rwset] == NULL)
2216 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d/",
2217 m->m_se_rwset);
2218 else
2219 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s/",
2220 RuleSetNames[m->m_se_rwset]);
2221 if (RuleSetNames[m->m_sh_rwset] == NULL)
2222 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d R=",
2223 m->m_sh_rwset);
2224 else
2225 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s R=",
2226 RuleSetNames[m->m_sh_rwset]);
2227 if (RuleSetNames[m->m_re_rwset] == NULL)
2228 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d/",
2229 m->m_re_rwset);
2230 else
2231 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s/",
2232 RuleSetNames[m->m_re_rwset]);
2233 if (RuleSetNames[m->m_rh_rwset] == NULL)
2234 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d ",
2235 m->m_rh_rwset);
2236 else
2237 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s ",
2238 RuleSetNames[m->m_rh_rwset]);
2239 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "M=%ld U=%d:%d F=",
2240 m->m_maxsize, (int) m->m_uid, (int) m->m_gid);
2241 for (j = '\0'; j <= '\177'; j++)
2242 if (bitnset(j, m->m_flags))
2243 (void) sm_io_putc(fp, SM_TIME_DEFAULT, j);
2244 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " L=%d E=",
2245 m->m_linelimit);
2246 xputs(fp, m->m_eol);
2247 if (m->m_defcharset != NULL)
2248 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " C=%s",
2249 m->m_defcharset);
2250 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " T=%s/%s/%s",
2251 m->m_mtatype == NULL
2252 ? "<undefined>" : m->m_mtatype,
2253 m->m_addrtype == NULL
2254 ? "<undefined>" : m->m_addrtype,
2255 m->m_diagtype == NULL
2256 ? "<undefined>" : m->m_diagtype);
2257 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " r=%d", m->m_maxrcpt);
2258 if (m->m_argv != NULL)
2259 {
2260 char **a = m->m_argv;
2261
2262 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " A=");
2263 while (*a != NULL)
2264 {
2265 if (a != m->m_argv)
2266 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2267 " ");
2268 xputs(fp, *a++);
2269 }
2270 }
2271 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\n");
2272 }
2273
2274 #if STARTTLS
2275 static struct ssl_options
2276 {
2277 const char *sslopt_name; /* name of the flag */
2278 long sslopt_bits; /* bits to set/clear */
2279 } SSL_Option[] =
2280 {
2281 /* Workaround for bugs are turned on by default (as well as some others) */
2282 # ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
2283 { "SSL_OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG },
2284 # endif
2285 # ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
2286 { "SSL_OP_NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG },
2287 # endif
2288 # ifdef SSL_OP_LEGACY_SERVER_CONNECT
2289 { "SSL_OP_LEGACY_SERVER_CONNECT", SSL_OP_LEGACY_SERVER_CONNECT },
2290 # endif
2291 # ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
2292 { "SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG },
2293 # endif
2294 # ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
2295 { "SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG },
2296 # endif
2297 # ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
2298 { "SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER },
2299 # endif
2300 # ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
2301 { "SSL_OP_MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING },
2302 # endif
2303 # ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
2304 { "SSL_OP_SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG },
2305 # endif
2306 # ifdef SSL_OP_TLS_D5_BUG
2307 { "SSL_OP_TLS_D5_BUG", SSL_OP_TLS_D5_BUG },
2308 # endif
2309 # ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
2310 { "SSL_OP_TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG },
2311 # endif
2312 # ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
2313 { "SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS },
2314 # endif
2315 # ifdef SSL_OP_ALL
2316 { "SSL_OP_ALL", SSL_OP_ALL },
2317 # endif
2318 # ifdef SSL_OP_NO_QUERY_MTU
2319 { "SSL_OP_NO_QUERY_MTU", SSL_OP_NO_QUERY_MTU },
2320 # endif
2321 # ifdef SSL_OP_COOKIE_EXCHANGE
2322 { "SSL_OP_COOKIE_EXCHANGE", SSL_OP_COOKIE_EXCHANGE },
2323 # endif
2324 # ifdef SSL_OP_NO_TICKET
2325 { "SSL_OP_NO_TICKET", SSL_OP_NO_TICKET },
2326 # endif
2327 # ifdef SSL_OP_CISCO_ANYCONNECT
2328 { "SSL_OP_CISCO_ANYCONNECT", SSL_OP_CISCO_ANYCONNECT },
2329 # endif
2330 # ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
2331 { "SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION },
2332 # endif
2333 # ifdef SSL_OP_NO_COMPRESSION
2334 { "SSL_OP_NO_COMPRESSION", SSL_OP_NO_COMPRESSION },
2335 # endif
2336 # ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
2337 { "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION },
2338 # endif
2339 # ifdef SSL_OP_SINGLE_ECDH_USE
2340 { "SSL_OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE },
2341 # endif
2342 # ifdef SSL_OP_SINGLE_DH_USE
2343 { "SSL_OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE },
2344 # endif
2345 # ifdef SSL_OP_EPHEMERAL_RSA
2346 { "SSL_OP_EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA },
2347 # endif
2348 # ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
2349 { "SSL_OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE },
2350 # endif
2351 # ifdef SSL_OP_TLS_ROLLBACK_BUG
2352 { "SSL_OP_TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG },
2353 # endif
2354 # ifdef SSL_OP_NO_SSLv2
2355 { "SSL_OP_NO_SSLv2", SSL_OP_NO_SSLv2 },
2356 # endif
2357 # ifdef SSL_OP_NO_SSLv3
2358 { "SSL_OP_NO_SSLv3", SSL_OP_NO_SSLv3 },
2359 # endif
2360 # ifdef SSL_OP_NO_TLSv1
2361 { "SSL_OP_NO_TLSv1", SSL_OP_NO_TLSv1 },
2362 # endif
2363 # ifdef SSL_OP_NO_TLSv1_3
2364 { "SSL_OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3 },
2365 # endif
2366 # ifdef SSL_OP_NO_TLSv1_2
2367 { "SSL_OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2 },
2368 # endif
2369 # ifdef SSL_OP_NO_TLSv1_1
2370 { "SSL_OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1 },
2371 # endif
2372 # ifdef SSL_OP_PKCS1_CHECK_1
2373 { "SSL_OP_PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1 },
2374 # endif
2375 # ifdef SSL_OP_PKCS1_CHECK_2
2376 { "SSL_OP_PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2 },
2377 # endif
2378 # ifdef SSL_OP_NETSCAPE_CA_DN_BUG
2379 { "SSL_OP_NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG },
2380 # endif
2381 # ifdef SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
2382 { "SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG },
2383 # endif
2384 # ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG
2385 { "SSL_OP_CRYPTOPRO_TLSEXT_BUG", SSL_OP_CRYPTOPRO_TLSEXT_BUG },
2386 # endif
2387 # ifdef SSL_OP_TLSEXT_PADDING
2388 { "SSL_OP_TLSEXT_PADDING", SSL_OP_TLSEXT_PADDING },
2389 # endif
2390 # ifdef SSL_OP_NO_RENEGOTIATION
2391 { "SSL_OP_NO_RENEGOTIATION", SSL_OP_NO_RENEGOTIATION },
2392 # endif
2393 # ifdef SSL_OP_NO_ANTI_REPLAY
2394 { "SSL_OP_NO_ANTI_REPLAY", SSL_OP_NO_ANTI_REPLAY },
2395 # endif
2396 # ifdef SSL_OP_ALLOW_NO_DHE_KEX
2397 { "SSL_OP_ALLOW_NO_DHE_KEX", SSL_OP_ALLOW_NO_DHE_KEX },
2398 # endif
2399 # ifdef SSL_OP_NO_ENCRYPT_THEN_MAC
2400 { "SSL_OP_NO_ENCRYPT_THEN_MAC", SSL_OP_NO_ENCRYPT_THEN_MAC },
2401 # endif
2402 # ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
2403 { "SSL_OP_ENABLE_MIDDLEBOX_COMPAT", SSL_OP_ENABLE_MIDDLEBOX_COMPAT },
2404 # endif
2405 # ifdef SSL_OP_PRIORITIZE_CHACHA
2406 { "SSL_OP_PRIORITIZE_CHACHA", SSL_OP_PRIORITIZE_CHACHA },
2407 # endif
2408 { NULL, 0 }
2409 };
2410
2411 /*
2412 ** READSSLOPTIONS -- read SSL_OP_* values
2413 **
2414 ** Parameters:
2415 ** opt -- name of option (can be NULL)
2416 ** val -- string with SSL_OP_* values or hex value
2417 ** delim -- end of string (e.g., '\0' or ';')
2418 ** pssloptions -- return value (output)
2419 **
2420 ** Returns:
2421 ** 0 on success.
2422 */
2423
2424 # define SSLOPERR_NAN 1
2425 # define SSLOPERR_NOTFOUND 2
2426
2427 static int readssloptions __P((char *, char *, unsigned long *, int ));
2428
2429 static int
readssloptions(opt,val,pssloptions,delim)2430 readssloptions(opt, val, pssloptions, delim)
2431 char *opt;
2432 char *val;
2433 unsigned long *pssloptions;
2434 int delim;
2435 {
2436 char *p;
2437 int ret;
2438
2439 ret = 0;
2440 for (p = val; *p != '\0' && *p != delim; )
2441 {
2442 bool clearmode;
2443 char *q;
2444 unsigned long sslopt_val;
2445 struct ssl_options *sslopts;
2446
2447 while (*p == ' ')
2448 p++;
2449 if (*p == '\0')
2450 break;
2451 clearmode = false;
2452 if (*p == '-' || *p == '+')
2453 clearmode = *p++ == '-';
2454 q = p;
2455 while (*p != '\0' && !(SM_ISSPACE(*p)) && *p != ',')
2456 p++;
2457 if (*p != '\0')
2458 *p++ = '\0';
2459 sslopt_val = 0;
2460 if (isdigit(*q))
2461 {
2462 char *end;
2463
2464 sslopt_val = strtoul(q, &end, 0);
2465
2466 /* not a complete "syntax" check but good enough */
2467 if (end == q)
2468 {
2469 errno = 0;
2470 ret = SSLOPERR_NAN;
2471 if (opt != NULL)
2472 syserr("readcf: %s option value %s not a number",
2473 opt, q);
2474 sslopt_val = 0;
2475 }
2476 }
2477 else
2478 {
2479 for (sslopts = SSL_Option;
2480 sslopts->sslopt_name != NULL; sslopts++)
2481 {
2482 if (SM_STRCASEEQ(q, sslopts->sslopt_name))
2483 {
2484 sslopt_val = sslopts->sslopt_bits;
2485 break;
2486 }
2487 }
2488 if (sslopts->sslopt_name == NULL)
2489 {
2490 errno = 0;
2491 ret = SSLOPERR_NOTFOUND;
2492 if (opt != NULL)
2493 syserr("readcf: %s option value %s unrecognized",
2494 opt, q);
2495 }
2496 }
2497 if (sslopt_val != 0)
2498 {
2499 if (clearmode)
2500 *pssloptions &= ~sslopt_val;
2501 else
2502 *pssloptions |= sslopt_val;
2503 }
2504 }
2505 return ret;
2506 }
2507
2508 /*
2509 ** GET_TLS_SE_FEATURES -- get TLS session features (from ruleset)
2510 **
2511 ** Parameters:
2512 ** e -- envelope
2513 ** ssl -- TLS session context
2514 ** tlsi_ctx -- TLS info context
2515 ** srv -- server?
2516 **
2517 ** Returns:
2518 ** EX_OK on success.
2519 */
2520
2521 int
get_tls_se_features(e,ssl,tlsi_ctx,srv)2522 get_tls_se_features(e, ssl, tlsi_ctx, srv)
2523 ENVELOPE *e;
2524 SSL *ssl;
2525 tlsi_ctx_T *tlsi_ctx;
2526 bool srv;
2527 {
2528 bool saveQuickAbort, saveSuprErrs;
2529 char *optionlist, *opt, *val;
2530 char *keyfile, *certfile;
2531 size_t len, i;
2532 int ret, rv;
2533
2534 # define who (srv ? "server" : "client")
2535 # define NAME_C_S macvalue(macid(srv ? "{client_name}" : "{server_name}"), e)
2536 # define ADDR_C_S macvalue(macid(srv ? "{client_addr}" : "{server_addr}"), e)
2537 # define WHICH srv ? "srv" : "clt"
2538
2539 SM_REQUIRE(ssl != NULL);
2540 rv = EX_OK;
2541 keyfile = certfile = opt = val = NULL;
2542 saveQuickAbort = QuickAbort;
2543 saveSuprErrs = SuprErrs;
2544 SuprErrs = true;
2545 QuickAbort = false;
2546 # if _FFR_MTA_STS
2547 SM_FREE(STS_SNI);
2548 # endif
2549
2550 optionlist = NULL;
2551 rv = rscheck(srv ? "tls_srv_features" : "tls_clt_features",
2552 NAME_C_S, ADDR_C_S, e,
2553 RSF_RMCOMM|RSF_ADDR|RSF_STRING,
2554 5, NULL, NOQID, NULL, &optionlist);
2555 if (EX_OK != rv && LogLevel > 8)
2556 {
2557 sm_syslog(LOG_NOTICE, NOQID,
2558 "rscheck(tls_%s_features)=failed, relay=%s [%s], errors=%d",
2559 WHICH, NAME_C_S, ADDR_C_S,
2560 Errors);
2561 }
2562 QuickAbort = saveQuickAbort;
2563 SuprErrs = saveSuprErrs;
2564 if (EX_OK == rv && LogLevel > 9)
2565 {
2566 sm_syslog(LOG_INFO, NOQID,
2567 "tls_%s_features=%s, relay=%s [%s]",
2568 WHICH, optionlist, NAME_C_S, ADDR_C_S);
2569 }
2570 if (EX_OK != rv || optionlist == NULL || (len = strlen(optionlist)) < 2)
2571 {
2572 if (LogLevel > 9)
2573 sm_syslog(LOG_INFO, NOQID,
2574 "tls_%s_features=empty, stat=%d, relay=%s [%s]",
2575 WHICH, rv, NAME_C_S, ADDR_C_S);
2576 return rv;
2577 }
2578
2579 i = 0;
2580 if (optionlist[0] == '"' && optionlist[len - 1] == '"')
2581 {
2582 optionlist[0] = ' ';
2583 optionlist[--len] = '\0';
2584 if (len <= 2)
2585 {
2586 if (LogLevel > 9 && len > 1)
2587 sm_syslog(LOG_INFO, NOQID,
2588 "tls_%s_features=too_short, relay=%s [%s]",
2589 WHICH, NAME_C_S, ADDR_C_S);
2590
2591 /* this is not treated as error! */
2592 return EX_OK;
2593 }
2594 i = 1;
2595 }
2596
2597 # define INVALIDSYNTAX \
2598 do { \
2599 if (LogLevel > 7) \
2600 sm_syslog(LOG_INFO, NOQID, \
2601 "tls_%s_features=invalid_syntax, opt=%s, relay=%s [%s]", \
2602 WHICH, opt, NAME_C_S, ADDR_C_S); \
2603 goto fail; \
2604 } while (0)
2605
2606 # define CHECKLEN \
2607 do { \
2608 if (i >= len) \
2609 INVALIDSYNTAX; \
2610 } while (0)
2611
2612 # define SKIPWS \
2613 do { \
2614 while (i < len && SM_ISSPACE(optionlist[i])) \
2615 ++i; \
2616 CHECKLEN; \
2617 } while (0)
2618
2619 /* parse and handle opt=val; */
2620 do {
2621 char sep;
2622
2623 SKIPWS;
2624 opt = optionlist + i;
2625 sep = '=';
2626 while (i < len && optionlist[i] != sep
2627 && optionlist[i] != '\0' && !SM_ISSPACE(optionlist[i]))
2628 ++i;
2629 CHECKLEN;
2630 while (i < len && SM_ISSPACE(optionlist[i]))
2631 optionlist[i++] = '\0';
2632 CHECKLEN;
2633 if (optionlist[i] != sep)
2634 INVALIDSYNTAX;
2635 optionlist[i++] = '\0';
2636
2637 SKIPWS;
2638 val = optionlist + i;
2639 sep = ';';
2640 while (i < len && optionlist[i] != sep && optionlist[i] != '\0')
2641 ++i;
2642 if (optionlist[i] != '\0')
2643 {
2644 CHECKLEN;
2645 optionlist[i++] = '\0';
2646 }
2647
2648 if (LogLevel > 13)
2649 sm_syslog(LOG_DEBUG, NOQID,
2650 "tls_%s_features=parsed, %s=%s, relay=%s [%s]",
2651 WHICH, opt, val, NAME_C_S, ADDR_C_S);
2652
2653 if (SM_STRCASEEQ(opt, "options"))
2654 {
2655 unsigned long ssloptions;
2656
2657 ssloptions = 0;
2658 ret = readssloptions(NULL, val, &ssloptions, ';');
2659 if (ret == 0)
2660 (void) SSL_set_options(ssl, (long) ssloptions);
2661 else
2662 {
2663 if (LogLevel > 8)
2664 {
2665 sm_syslog(LOG_WARNING, NOQID,
2666 "tls_%s_features=%s, error=%s, relay=%s [%s]",
2667 WHICH, val,
2668 (ret == SSLOPERR_NAN) ? "not a number" :
2669 ((ret == SSLOPERR_NOTFOUND) ? "SSL_OP not found" :
2670 "unknown"),
2671 NAME_C_S, ADDR_C_S);
2672 }
2673 goto fail;
2674 }
2675 }
2676 else if (SM_STRCASEEQ(opt, "cipherlist"))
2677 {
2678 if (SSL_set_cipher_list(ssl, val) <= 0)
2679 {
2680 if (LogLevel > 7)
2681 {
2682 sm_syslog(LOG_WARNING, NOQID,
2683 "STARTTLS=%s, error: SSL_set_cipher_list(%s) failed",
2684 who, val);
2685
2686 tlslogerr(LOG_WARNING, 9, who);
2687 }
2688 goto fail;
2689 }
2690 }
2691 # if MTA_HAVE_TLSv1_3
2692 else if (SM_STRCASEEQ(opt, "ciphersuites"))
2693 {
2694 if (SSL_set_ciphersuites(ssl, val) <= 0)
2695 {
2696 if (LogLevel > 7)
2697 {
2698 sm_syslog(LOG_WARNING, NOQID,
2699 "STARTTLS=%s, error: SSL_set_ciphersuites(%s) failed",
2700 who, val);
2701
2702 tlslogerr(LOG_WARNING, 9, who);
2703 }
2704 goto fail;
2705 }
2706 }
2707 # endif /* MTA_HAVE_TLSv1_3 */
2708 else if (SM_STRCASEEQ(opt, "flags"))
2709 {
2710 char *p;
2711
2712 for (p = val; *p != '\0'; p++)
2713 {
2714 if (isascii(*p) && isalnum(*p))
2715 setbitn(bitidx(*p), tlsi_ctx->tlsi_flags);
2716 }
2717 }
2718 else if (SM_STRCASEEQ(opt, "keyfile"))
2719 keyfile = val;
2720 else if (SM_STRCASEEQ(opt, "certfile"))
2721 certfile = val;
2722 # if _FFR_MTA_STS
2723 else if (sm_strcasecmp(opt, "servername") == 0 &&
2724 sm_strcasecmp(val, "hostname") == 0)
2725 {
2726 char *sn;
2727
2728 sn = macvalue(macid("{server_name}"), e);
2729 if (sn == NULL)
2730 STS_SNI = NULL;
2731 else
2732 STS_SNI = sm_strdup(sn);
2733 }
2734 else if (sm_strcasecmp(opt, "servername") == 0)
2735 {
2736 if (LogLevel > 7)
2737 {
2738 sm_syslog(LOG_INFO, NOQID,
2739 "tls_%s_features=servername, invalid_value=%s, relay=%s [%s]",
2740 WHICH, val, NAME_C_S, ADDR_C_S);
2741 }
2742 goto fail;
2743 }
2744 else if (sm_strcasecmp(opt, "sts") == 0 &&
2745 sm_strcasecmp(val, "secure") == 0)
2746 setbitn(bitidx(TLSI_FL_STS_NOFB2CLR), tlsi_ctx->tlsi_flags);
2747 # endif /* _FFR_MTA_STS */
2748 else
2749 {
2750 if (LogLevel > 7)
2751 {
2752 sm_syslog(LOG_INFO, NOQID,
2753 "tls_%s_features=unknown_option, opt=%s, relay=%s [%s]",
2754 WHICH, opt, NAME_C_S, ADDR_C_S);
2755 }
2756 goto fail;
2757 }
2758
2759 } while (optionlist[i] != '\0' && i < len);
2760
2761 /* need cert and key before we can use the options */
2762 /* does not implement the "," hack for 2nd cert/key pair */
2763 if (keyfile != NULL && certfile != NULL)
2764 {
2765 load_certkey(ssl, srv, certfile, keyfile);
2766 keyfile = certfile = NULL;
2767 }
2768 else if (keyfile != NULL || certfile != NULL)
2769 {
2770 if (LogLevel > 7)
2771 {
2772 sm_syslog(LOG_INFO, NOQID,
2773 "tls_%s_features=only_one_of_CertFile/KeyFile_specified, relay=%s [%s]",
2774 WHICH, NAME_C_S, ADDR_C_S);
2775 }
2776 goto fail;
2777 }
2778
2779 return rv;
2780
2781 fail:
2782 return EX_CONFIG;
2783 # undef who
2784 # undef NAME_C_S
2785 # undef ADDR_C_S
2786 # undef WHICH
2787 }
2788 #endif /* STARTTLS */
2789
2790 /*
2791 ** SETOPTION -- set global processing option
2792 **
2793 ** Parameters:
2794 ** opt -- option name.
2795 ** val -- option value (as a text string).
2796 ** safe -- set if this came from a configuration file.
2797 ** Some options (if set from the command line) will
2798 ** reset the user id to avoid security problems.
2799 ** sticky -- if set, don't let other setoptions override
2800 ** this value.
2801 ** e -- the main envelope.
2802 **
2803 ** Returns:
2804 ** none.
2805 **
2806 ** Side Effects:
2807 ** Sets options as implied by the arguments.
2808 */
2809
2810 static BITMAP256 StickyOpt; /* set if option is stuck */
2811
2812 #if NAMED_BIND
2813
2814 static struct resolverflags
2815 {
2816 char *rf_name; /* name of the flag */
2817 long rf_bits; /* bits to set/clear */
2818 } ResolverFlags[] =
2819 {
2820 { "debug", RES_DEBUG },
2821 { "aaonly", RES_AAONLY },
2822 { "usevc", RES_USEVC },
2823 { "primary", RES_PRIMARY },
2824 { "igntc", RES_IGNTC },
2825 { "recurse", RES_RECURSE },
2826 { "defnames", RES_DEFNAMES },
2827 { "stayopen", RES_STAYOPEN },
2828 { "dnsrch", RES_DNSRCH },
2829 # ifdef RES_USE_INET6
2830 { "use_inet6", RES_USE_INET6 },
2831 # endif
2832 # ifdef RES_USE_EDNS0
2833 { "use_edns0", RES_USE_EDNS0 },
2834 # endif
2835 # ifdef RES_USE_DNSSEC
2836 { "use_dnssec", RES_USE_DNSSEC },
2837 # endif
2838 # if RES_TRUSTAD
2839 { "trustad", RES_TRUSTAD },
2840 # endif
2841 { "true", 0 }, /* avoid error on old syntax */
2842 { "true", 0 }, /* avoid error on old syntax */
2843 { NULL, 0 }
2844 };
2845
2846 #endif /* NAMED_BIND */
2847
2848 #define OI_NONE 0 /* no special treatment */
2849 #define OI_SAFE 0x0001 /* safe for random people to use */
2850 #define OI_SUBOPT 0x0002 /* option has suboptions */
2851
2852 static struct optioninfo
2853 {
2854 char *o_name; /* long name of option */
2855 unsigned char o_code; /* short name of option */
2856 unsigned short o_flags; /* option flags */
2857 } OptionTab[] =
2858 {
2859 #if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE)
2860 { "RemoteMode", '>', OI_NONE },
2861 #endif
2862 { "SevenBitInput", '7', OI_SAFE },
2863 { "EightBitMode", '8', OI_SAFE },
2864 { "AliasFile", 'A', OI_NONE },
2865 { "AliasWait", 'a', OI_NONE },
2866 { "BlankSub", 'B', OI_NONE },
2867 { "MinFreeBlocks", 'b', OI_SAFE },
2868 { "CheckpointInterval", 'C', OI_SAFE },
2869 { "HoldExpensive", 'c', OI_NONE },
2870 { "DeliveryMode", 'd', OI_SAFE },
2871 { "ErrorHeader", 'E', OI_NONE },
2872 { "ErrorMode", 'e', OI_SAFE },
2873 { "TempFileMode", 'F', OI_NONE },
2874 { "SaveFromLine", 'f', OI_NONE },
2875 { "MatchGECOS", 'G', OI_NONE },
2876
2877 /* no long name, just here to avoid problems in setoption */
2878 { "", 'g', OI_NONE },
2879 { "HelpFile", 'H', OI_NONE },
2880 { "MaxHopCount", 'h', OI_NONE },
2881 { "ResolverOptions", 'I', OI_NONE },
2882 { "IgnoreDots", 'i', OI_SAFE },
2883 { "ForwardPath", 'J', OI_NONE },
2884 { "SendMimeErrors", 'j', OI_SAFE },
2885 { "ConnectionCacheSize", 'k', OI_NONE },
2886 { "ConnectionCacheTimeout", 'K', OI_NONE },
2887 { "UseErrorsTo", 'l', OI_NONE },
2888 { "LogLevel", 'L', OI_SAFE },
2889 { "MeToo", 'm', OI_SAFE },
2890
2891 /* no long name, just here to avoid problems in setoption */
2892 { "", 'M', OI_NONE },
2893 { "CheckAliases", 'n', OI_NONE },
2894 { "OldStyleHeaders", 'o', OI_SAFE },
2895 { "DaemonPortOptions", 'O', OI_NONE },
2896 { "PrivacyOptions", 'p', OI_SAFE },
2897 { "PostmasterCopy", 'P', OI_NONE },
2898 { "QueueFactor", 'q', OI_NONE },
2899 { "QueueDirectory", 'Q', OI_NONE },
2900 { "DontPruneRoutes", 'R', OI_NONE },
2901 { "Timeout", 'r', OI_SUBOPT },
2902 { "StatusFile", 'S', OI_NONE },
2903 { "SuperSafe", 's', OI_SAFE },
2904 { "QueueTimeout", 'T', OI_NONE },
2905 { "TimeZoneSpec", 't', OI_NONE },
2906 { "UserDatabaseSpec", 'U', OI_NONE },
2907 { "DefaultUser", 'u', OI_NONE },
2908 { "FallbackMXhost", 'V', OI_NONE },
2909 { "Verbose", 'v', OI_SAFE },
2910 { "TryNullMXList", 'w', OI_NONE },
2911 { "QueueLA", 'x', OI_NONE },
2912 { "RefuseLA", 'X', OI_NONE },
2913 { "RecipientFactor", 'y', OI_NONE },
2914 { "ForkEachJob", 'Y', OI_NONE },
2915 { "ClassFactor", 'z', OI_NONE },
2916 { "RetryFactor", 'Z', OI_NONE },
2917 #define O_QUEUESORTORD 0x81
2918 { "QueueSortOrder", O_QUEUESORTORD, OI_SAFE },
2919 #define O_HOSTSFILE 0x82
2920 { "HostsFile", O_HOSTSFILE, OI_NONE },
2921 #define O_MQA 0x83
2922 { "MinQueueAge", O_MQA, OI_SAFE },
2923 #define O_DEFCHARSET 0x85
2924 { "DefaultCharSet", O_DEFCHARSET, OI_SAFE },
2925 #define O_SSFILE 0x86
2926 { "ServiceSwitchFile", O_SSFILE, OI_NONE },
2927 #define O_DIALDELAY 0x87
2928 { "DialDelay", O_DIALDELAY, OI_SAFE },
2929 #define O_NORCPTACTION 0x88
2930 { "NoRecipientAction", O_NORCPTACTION, OI_SAFE },
2931 #define O_SAFEFILEENV 0x89
2932 { "SafeFileEnvironment", O_SAFEFILEENV, OI_NONE },
2933 #define O_MAXMSGSIZE 0x8a
2934 { "MaxMessageSize", O_MAXMSGSIZE, OI_NONE },
2935 #define O_COLONOKINADDR 0x8b
2936 { "ColonOkInAddr", O_COLONOKINADDR, OI_SAFE },
2937 #define O_MAXQUEUERUN 0x8c
2938 { "MaxQueueRunSize", O_MAXQUEUERUN, OI_SAFE },
2939 #define O_MAXCHILDREN 0x8d
2940 { "MaxDaemonChildren", O_MAXCHILDREN, OI_NONE },
2941 #define O_KEEPCNAMES 0x8e
2942 { "DontExpandCnames", O_KEEPCNAMES, OI_NONE },
2943 #define O_MUSTQUOTE 0x8f
2944 { "MustQuoteChars", O_MUSTQUOTE, OI_NONE },
2945 #define O_SMTPGREETING 0x90
2946 { "SmtpGreetingMessage", O_SMTPGREETING, OI_NONE },
2947 #define O_UNIXFROM 0x91
2948 { "UnixFromLine", O_UNIXFROM, OI_NONE },
2949 #define O_OPCHARS 0x92
2950 { "OperatorChars", O_OPCHARS, OI_NONE },
2951 #define O_DONTINITGRPS 0x93
2952 { "DontInitGroups", O_DONTINITGRPS, OI_NONE },
2953 #define O_SLFH 0x94
2954 { "SingleLineFromHeader", O_SLFH, OI_SAFE },
2955 #define O_ABH 0x95
2956 { "AllowBogusHELO", O_ABH, OI_SAFE },
2957 #define O_CONNTHROT 0x97
2958 { "ConnectionRateThrottle", O_CONNTHROT, OI_NONE },
2959 #define O_UGW 0x99
2960 { "UnsafeGroupWrites", O_UGW, OI_NONE },
2961 #define O_DBLBOUNCE 0x9a
2962 { "DoubleBounceAddress", O_DBLBOUNCE, OI_NONE },
2963 #define O_HSDIR 0x9b
2964 { "HostStatusDirectory", O_HSDIR, OI_NONE },
2965 #define O_SINGTHREAD 0x9c
2966 { "SingleThreadDelivery", O_SINGTHREAD, OI_NONE },
2967 #define O_RUNASUSER 0x9d
2968 { "RunAsUser", O_RUNASUSER, OI_NONE },
2969 #define O_DSN_RRT 0x9e
2970 { "RrtImpliesDsn", O_DSN_RRT, OI_NONE },
2971 #define O_PIDFILE 0x9f
2972 { "PidFile", O_PIDFILE, OI_NONE },
2973 #define O_DONTBLAMESENDMAIL 0xa0
2974 { "DontBlameSendmail", O_DONTBLAMESENDMAIL, OI_NONE },
2975 #define O_DPI 0xa1
2976 { "DontProbeInterfaces", O_DPI, OI_NONE },
2977 #define O_MAXRCPT 0xa2
2978 { "MaxRecipientsPerMessage", O_MAXRCPT, OI_SAFE },
2979 #define O_DEADLETTER 0xa3
2980 { "DeadLetterDrop", O_DEADLETTER, OI_NONE },
2981 #if _FFR_DONTLOCKFILESFORREAD_OPTION
2982 # define O_DONTLOCK 0xa4
2983 { "DontLockFilesForRead", O_DONTLOCK, OI_NONE },
2984 #endif
2985 #define O_MAXALIASRCSN 0xa5
2986 { "MaxAliasRecursion", O_MAXALIASRCSN, OI_NONE },
2987 #define O_CNCTONLYTO 0xa6
2988 { "ConnectOnlyTo", O_CNCTONLYTO, OI_NONE },
2989 #define O_TRUSTUSER 0xa7
2990 { "TrustedUser", O_TRUSTUSER, OI_NONE },
2991 #define O_MAXMIMEHDRLEN 0xa8
2992 { "MaxMimeHeaderLength", O_MAXMIMEHDRLEN, OI_NONE },
2993 #define O_CONTROLSOCKET 0xa9
2994 { "ControlSocketName", O_CONTROLSOCKET, OI_NONE },
2995 #define O_MAXHDRSLEN 0xaa
2996 { "MaxHeadersLength", O_MAXHDRSLEN, OI_NONE },
2997 #if _FFR_MAX_FORWARD_ENTRIES
2998 # define O_MAXFORWARD 0xab
2999 { "MaxForwardEntries", O_MAXFORWARD, OI_NONE },
3000 #endif
3001 #define O_PROCTITLEPREFIX 0xac
3002 { "ProcessTitlePrefix", O_PROCTITLEPREFIX, OI_NONE },
3003 #define O_SASLINFO 0xad
3004 #if _FFR_ALLOW_SASLINFO
3005 { "DefaultAuthInfo", O_SASLINFO, OI_SAFE },
3006 #else
3007 { "DefaultAuthInfo", O_SASLINFO, OI_NONE },
3008 #endif
3009 #define O_SASLMECH 0xae
3010 { "AuthMechanisms", O_SASLMECH, OI_NONE },
3011 #define O_CLIENTPORT 0xaf
3012 { "ClientPortOptions", O_CLIENTPORT, OI_NONE },
3013 #define O_DF_BUFSIZE 0xb0
3014 { "DataFileBufferSize", O_DF_BUFSIZE, OI_NONE },
3015 #define O_XF_BUFSIZE 0xb1
3016 { "XscriptFileBufferSize", O_XF_BUFSIZE, OI_NONE },
3017 #define O_LDAPDEFAULTSPEC 0xb2
3018 { "LDAPDefaultSpec", O_LDAPDEFAULTSPEC, OI_NONE },
3019 #define O_SRVCERTFILE 0xb4
3020 { "ServerCertFile", O_SRVCERTFILE, OI_NONE },
3021 #define O_SRVKEYFILE 0xb5
3022 { "ServerKeyFile", O_SRVKEYFILE, OI_NONE },
3023 #define O_CLTCERTFILE 0xb6
3024 { "ClientCertFile", O_CLTCERTFILE, OI_NONE },
3025 #define O_CLTKEYFILE 0xb7
3026 { "ClientKeyFile", O_CLTKEYFILE, OI_NONE },
3027 #define O_CACERTFILE 0xb8
3028 { "CACertFile", O_CACERTFILE, OI_NONE },
3029 #define O_CACERTPATH 0xb9
3030 { "CACertPath", O_CACERTPATH, OI_NONE },
3031 #define O_DHPARAMS 0xba
3032 { "DHParameters", O_DHPARAMS, OI_NONE },
3033 #define O_INPUTMILTER 0xbb
3034 { "InputMailFilters", O_INPUTMILTER, OI_NONE },
3035 #define O_MILTER 0xbc
3036 { "Milter", O_MILTER, OI_SUBOPT },
3037 #define O_SASLOPTS 0xbd
3038 { "AuthOptions", O_SASLOPTS, OI_NONE },
3039 #define O_QUEUE_FILE_MODE 0xbe
3040 { "QueueFileMode", O_QUEUE_FILE_MODE, OI_NONE },
3041 #define O_DIG_ALG 0xbf
3042 { "CertFingerprintAlgorithm", O_DIG_ALG, OI_NONE },
3043 #define O_CIPHERLIST 0xc0
3044 { "CipherList", O_CIPHERLIST, OI_NONE },
3045 #define O_RANDFILE 0xc1
3046 { "RandFile", O_RANDFILE, OI_NONE },
3047 #define O_TLS_SRV_OPTS 0xc2
3048 { "TLSSrvOptions", O_TLS_SRV_OPTS, OI_NONE },
3049 #define O_RCPTTHROT 0xc3
3050 { "BadRcptThrottle", O_RCPTTHROT, OI_SAFE },
3051 #define O_DLVR_MIN 0xc4
3052 { "DeliverByMin", O_DLVR_MIN, OI_NONE },
3053 #define O_MAXQUEUECHILDREN 0xc5
3054 { "MaxQueueChildren", O_MAXQUEUECHILDREN, OI_NONE },
3055 #define O_MAXRUNNERSPERQUEUE 0xc6
3056 { "MaxRunnersPerQueue", O_MAXRUNNERSPERQUEUE, OI_NONE },
3057 #define O_DIRECTSUBMODIFIERS 0xc7
3058 { "DirectSubmissionModifiers", O_DIRECTSUBMODIFIERS, OI_NONE },
3059 #define O_NICEQUEUERUN 0xc8
3060 { "NiceQueueRun", O_NICEQUEUERUN, OI_NONE },
3061 #define O_SHMKEY 0xc9
3062 { "SharedMemoryKey", O_SHMKEY, OI_NONE },
3063 #define O_SASLBITS 0xca
3064 { "AuthMaxBits", O_SASLBITS, OI_NONE },
3065 #define O_MBDB 0xcb
3066 { "MailboxDatabase", O_MBDB, OI_NONE },
3067 #define O_MSQ 0xcc
3068 { "UseMSP", O_MSQ, OI_NONE },
3069 #define O_DELAY_LA 0xcd
3070 { "DelayLA", O_DELAY_LA, OI_NONE },
3071 #define O_FASTSPLIT 0xce
3072 { "FastSplit", O_FASTSPLIT, OI_NONE },
3073 #define O_SOFTBOUNCE 0xcf
3074 { "SoftBounce", O_SOFTBOUNCE, OI_NONE },
3075 #define O_SHMKEYFILE 0xd0
3076 { "SharedMemoryKeyFile", O_SHMKEYFILE, OI_NONE },
3077 #define O_REJECTLOGINTERVAL 0xd1
3078 { "RejectLogInterval", O_REJECTLOGINTERVAL, OI_NONE },
3079 #define O_REQUIRES_DIR_FSYNC 0xd2
3080 { "RequiresDirfsync", O_REQUIRES_DIR_FSYNC, OI_NONE },
3081 #define O_CONNECTION_RATE_WINDOW_SIZE 0xd3
3082 { "ConnectionRateWindowSize", O_CONNECTION_RATE_WINDOW_SIZE, OI_NONE },
3083 #define O_CRLFILE 0xd4
3084 { "CRLFile", O_CRLFILE, OI_NONE },
3085 #define O_FALLBACKSMARTHOST 0xd5
3086 { "FallbackSmartHost", O_FALLBACKSMARTHOST, OI_NONE },
3087 #define O_SASLREALM 0xd6
3088 { "AuthRealm", O_SASLREALM, OI_NONE },
3089 #define O_CRLPATH 0xd7
3090 { "CRLPath", O_CRLPATH, OI_NONE },
3091 #define O_HELONAME 0xd8
3092 { "HeloName", O_HELONAME, OI_NONE },
3093 #if _FFR_MEMSTAT
3094 # define O_REFUSELOWMEM 0xd9
3095 { "RefuseLowMem", O_REFUSELOWMEM, OI_NONE },
3096 # define O_QUEUELOWMEM 0xda
3097 { "QueueLowMem", O_QUEUELOWMEM, OI_NONE },
3098 # define O_MEMRESOURCE 0xdb
3099 { "MemoryResource", O_MEMRESOURCE, OI_NONE },
3100 #endif /* _FFR_MEMSTAT */
3101 #define O_MAXNOOPCOMMANDS 0xdc
3102 { "MaxNOOPCommands", O_MAXNOOPCOMMANDS, OI_NONE },
3103 #if _FFR_MSG_ACCEPT
3104 # define O_MSG_ACCEPT 0xdd
3105 { "MessageAccept", O_MSG_ACCEPT, OI_NONE },
3106 #endif
3107 #if _FFR_QUEUE_RUN_PARANOIA
3108 # define O_CHK_Q_RUNNERS 0xde
3109 { "CheckQueueRunners", O_CHK_Q_RUNNERS, OI_NONE },
3110 #endif
3111 #if _FFR_EIGHT_BIT_ADDR_OK
3112 # if !ALLOW_255
3113 # error "_FFR_EIGHT_BIT_ADDR_OK requires ALLOW_255"
3114 # endif
3115 # define O_EIGHT_BIT_ADDR_OK 0xdf
3116 { "EightBitAddrOK", O_EIGHT_BIT_ADDR_OK, OI_NONE },
3117 #endif /* _FFR_EIGHT_BIT_ADDR_OK */
3118 #if _FFR_ADDR_TYPE_MODES
3119 # define O_ADDR_TYPE_MODES 0xe0
3120 { "AddrTypeModes", O_ADDR_TYPE_MODES, OI_NONE },
3121 #endif
3122 #if _FFR_BADRCPT_SHUTDOWN
3123 # define O_RCPTSHUTD 0xe1
3124 { "BadRcptShutdown", O_RCPTSHUTD, OI_SAFE },
3125 # define O_RCPTSHUTDG 0xe2
3126 { "BadRcptShutdownGood", O_RCPTSHUTDG, OI_SAFE },
3127 #endif /* _FFR_BADRCPT_SHUTDOWN */
3128 #define O_SRV_SSL_OPTIONS 0xe3
3129 { "ServerSSLOptions", O_SRV_SSL_OPTIONS, OI_NONE },
3130 #define O_CLT_SSL_OPTIONS 0xe4
3131 { "ClientSSLOptions", O_CLT_SSL_OPTIONS, OI_NONE },
3132 #define O_MAX_QUEUE_AGE 0xe5
3133 { "MaxQueueAge", O_MAX_QUEUE_AGE, OI_NONE },
3134 #if _FFR_RCPTTHROTDELAY
3135 # define O_RCPTTHROTDELAY 0xe6
3136 { "BadRcptThrottleDelay", O_RCPTTHROTDELAY, OI_SAFE },
3137 #endif
3138 #if 0 && _FFR_QOS && defined(SOL_IP) && defined(IP_TOS)
3139 # define O_INETQOS 0xe7 /* reserved for FFR_QOS */
3140 { "InetQoS", O_INETQOS, OI_NONE },
3141 #endif
3142 #if STARTTLS && _FFR_FIPSMODE
3143 # define O_FIPSMODE 0xe8
3144 { "FIPSMode", O_FIPSMODE, OI_NONE },
3145 #endif
3146 #if _FFR_REJECT_NUL_BYTE
3147 # define O_REJECTNUL 0xe9
3148 { "RejectNUL", O_REJECTNUL, OI_SAFE },
3149 #endif
3150 #if _FFR_BOUNCE_QUEUE
3151 # define O_BOUNCEQUEUE 0xea
3152 { "BounceQueue", O_BOUNCEQUEUE, OI_NONE },
3153 #endif
3154 #if _FFR_ADD_BCC
3155 # define O_ADDBCC 0xeb
3156 { "AddBcc", O_ADDBCC, OI_NONE },
3157 #endif
3158 #define O_USECOMPRESSEDIPV6ADDRESSES 0xec
3159 { "UseCompressedIPv6Addresses", O_USECOMPRESSEDIPV6ADDRESSES, OI_NONE },
3160 #if STARTTLS
3161 # define O_SSLENGINE 0xed
3162 { "SSLEngine", O_SSLENGINE, OI_NONE },
3163 # define O_SSLENGINEPATH 0xee
3164 { "SSLEnginePath", O_SSLENGINEPATH, OI_NONE },
3165 # define O_TLSFB2CLEAR 0xef
3166 { "TLSFallbacktoClear", O_TLSFB2CLEAR, OI_NONE },
3167 #endif
3168 #if DNSSEC_TEST || _FFR_NAMESERVER
3169 # define O_NSPORTIP 0xf0
3170 { "NameServer", O_NSPORTIP, OI_NONE },
3171 #endif
3172 #if DANE
3173 # define O_DANE 0xf1
3174 { "DANE", O_DANE, OI_NONE },
3175 #endif
3176 #if DNSSEC_TEST || _FFR_NAMESERVER
3177 # define O_NSSRCHLIST 0xf2
3178 { "NameSearchList", O_NSSRCHLIST, OI_NONE },
3179 #endif
3180 #if _FFR_BLANKENV_MACV
3181 # define O_HACKS 0xf4
3182 { "Hacks", O_HACKS, OI_NONE },
3183 #endif
3184 #if _FFR_KEEPBCC
3185 # define O_KEEPBCC 0xf3
3186 { "KeepBcc", O_KEEPBCC, OI_NONE },
3187 #endif
3188
3189 #if _FFR_CLIENTCA
3190 #define O_CLTCACERTFILE 0xf5
3191 { "ClientCACertFile", O_CLTCACERTFILE, OI_NONE },
3192 #define O_CLTCACERTPATH 0xf6
3193 { "ClientCACertPath", O_CLTCACERTPATH, OI_NONE },
3194 #endif
3195 #if _FFR_TLS_ALTNAMES
3196 # define O_CHECKALTNAMES 0xf7
3197 { "SetCertAltnames", O_CHECKALTNAMES, OI_NONE },
3198 #endif
3199 #define O_SMTPUTF8 0xf8
3200 { "SmtpUTF8", O_SMTPUTF8, OI_NONE },
3201 #if _FFR_MTA_STS
3202 # define O_MTASTS 0xf9
3203 { "StrictTransportSecurity", O_MTASTS, OI_NONE },
3204 #endif
3205
3206 #if MTA_HAVE_TLSv1_3
3207 #define O_CIPHERSUITES 0xfa
3208 { "CipherSuites", O_CIPHERSUITES, OI_NONE },
3209 #endif
3210
3211 { NULL, '\0', OI_NONE }
3212 };
3213
3214 # define CANONIFY(val)
3215
3216 # define SET_OPT_DEFAULT(opt, val) opt = val
3217
3218 /* set a string option by expanding the value and assigning it */
3219 /* WARNING this belongs ONLY into a case statement! */
3220 #define SET_STRING_EXP(str) \
3221 expand(val, exbuf, sizeof(exbuf), e); \
3222 newval = sm_pstrdup_x(exbuf); \
3223 if (str != NULL) \
3224 sm_free(str); \
3225 CANONIFY(newval); \
3226 str = newval; \
3227 break
3228
3229 #define OPTNAME o->o_name == NULL ? "<unknown>" : o->o_name
3230
3231 void
setoption(opt,val,safe,sticky,e)3232 setoption(opt, val, safe, sticky, e)
3233 int opt;
3234 char *val;
3235 bool safe;
3236 bool sticky;
3237 register ENVELOPE *e;
3238 {
3239 register char *p;
3240 register struct optioninfo *o;
3241 char *subopt;
3242 int i;
3243 bool can_setuid = RunAsUid == 0;
3244 auto char *ep;
3245 char buf[50];
3246 extern bool Warn_Q_option;
3247 #if _FFR_ALLOW_SASLINFO
3248 extern unsigned int SubmitMode;
3249 #endif
3250 #if STARTTLS || SM_CONF_SHM
3251 char *newval;
3252 char exbuf[MAXLINE];
3253 #endif
3254 #if STARTTLS
3255 unsigned long *pssloptions = NULL;
3256 #endif
3257
3258 errno = 0;
3259 if (opt == ' ')
3260 {
3261 /* full word options */
3262 struct optioninfo *sel;
3263
3264 p = strchr(val, '=');
3265 if (p == NULL)
3266 p = &val[strlen(val)];
3267 while (*--p == ' ')
3268 continue;
3269 while (*++p == ' ')
3270 *p = '\0';
3271 if (p == val)
3272 {
3273 syserr("readcf: null option name");
3274 return;
3275 }
3276 if (*p == '=')
3277 *p++ = '\0';
3278 while (*p == ' ')
3279 p++;
3280 subopt = strchr(val, '.');
3281 if (subopt != NULL)
3282 *subopt++ = '\0';
3283 sel = NULL;
3284 for (o = OptionTab; o->o_name != NULL; o++)
3285 {
3286 if (sm_strncasecmp(o->o_name, val, strlen(val)) != 0)
3287 continue;
3288 if (strlen(o->o_name) == strlen(val))
3289 {
3290 /* completely specified -- this must be it */
3291 sel = NULL;
3292 break;
3293 }
3294 if (sel != NULL)
3295 break;
3296 sel = o;
3297 }
3298 if (sel != NULL && o->o_name == NULL)
3299 o = sel;
3300 else if (o->o_name == NULL)
3301 {
3302 syserr("readcf: unknown option name %s", val);
3303 return;
3304 }
3305 else if (sel != NULL)
3306 {
3307 syserr("readcf: ambiguous option name %s (matches %s and %s)",
3308 val, sel->o_name, o->o_name);
3309 return;
3310 }
3311 if (strlen(val) != strlen(o->o_name))
3312 {
3313 int oldVerbose = Verbose;
3314
3315 Verbose = 1;
3316 message("Option %s used as abbreviation for %s",
3317 val, o->o_name);
3318 Verbose = oldVerbose;
3319 }
3320 opt = o->o_code;
3321 val = p;
3322 }
3323 else
3324 {
3325 for (o = OptionTab; o->o_name != NULL; o++)
3326 {
3327 if (o->o_code == opt)
3328 break;
3329 }
3330 if (o->o_name == NULL)
3331 {
3332 syserr("readcf: unknown option name 0x%x", opt & 0xff);
3333 return;
3334 }
3335 subopt = NULL;
3336 }
3337
3338 if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags))
3339 {
3340 if (tTd(37, 1))
3341 sm_dprintf("setoption: %s does not support suboptions, ignoring .%s\n",
3342 OPTNAME, subopt);
3343 subopt = NULL;
3344 }
3345
3346 if (tTd(37, 1))
3347 {
3348 sm_dprintf(isascii(opt) && isprint(opt) ?
3349 "setoption %s (%c)%s%s=" :
3350 "setoption %s (0x%x)%s%s=",
3351 OPTNAME, opt, subopt == NULL ? "" : ".",
3352 subopt == NULL ? "" : subopt);
3353 xputs(sm_debug_file(), val);
3354 }
3355
3356 /*
3357 ** See if this option is preset for us.
3358 */
3359
3360 if (!sticky && bitnset(opt, StickyOpt))
3361 {
3362 if (tTd(37, 1))
3363 sm_dprintf(" (ignored)\n");
3364 return;
3365 }
3366
3367 /*
3368 ** Check to see if this option can be specified by this user.
3369 */
3370
3371 if (!safe && RealUid == 0)
3372 safe = true;
3373 if (!safe && !bitset(OI_SAFE, o->o_flags))
3374 {
3375 if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
3376 {
3377 int dp;
3378
3379 if (tTd(37, 1))
3380 sm_dprintf(" (unsafe)");
3381 dp = drop_privileges(true);
3382 setstat(dp);
3383 }
3384 }
3385 if (tTd(37, 1))
3386 sm_dprintf("\n");
3387
3388 switch (opt & 0xff)
3389 {
3390 case '7': /* force seven-bit input */
3391 SevenBitInput = atobool(val);
3392 break;
3393
3394 case '8': /* handling of 8-bit input */
3395 #if MIME8TO7
3396 switch (*val)
3397 {
3398 case 'p': /* pass 8 bit, convert MIME */
3399 MimeMode = MM_CVTMIME|MM_PASS8BIT;
3400 break;
3401
3402 case 'm': /* convert 8-bit, convert MIME */
3403 MimeMode = MM_CVTMIME|MM_MIME8BIT;
3404 break;
3405
3406 case 's': /* strict adherence */
3407 MimeMode = MM_CVTMIME;
3408 break;
3409
3410 # if 0
3411 case 'r': /* reject 8-bit, don't convert MIME */
3412 MimeMode = 0;
3413 break;
3414
3415 case 'j': /* "just send 8" */
3416 MimeMode = MM_PASS8BIT;
3417 break;
3418
3419 case 'a': /* encode 8 bit if available */
3420 MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
3421 break;
3422
3423 case 'c': /* convert 8 bit to MIME, never 7 bit */
3424 MimeMode = MM_MIME8BIT;
3425 break;
3426 # endif /* 0 */
3427
3428 default:
3429 syserr("Unknown 8-bit mode %c", *val);
3430 finis(false, true, EX_USAGE);
3431 }
3432 #else /* MIME8TO7 */
3433 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3434 "Warning: Option: %s requires MIME8TO7 support\n",
3435 OPTNAME);
3436 #endif /* MIME8TO7 */
3437 break;
3438
3439 case 'A': /* set default alias file */
3440 if (val[0] == '\0')
3441 {
3442 char *al;
3443
3444 SET_OPT_DEFAULT(al, "aliases");
3445 setalias(al);
3446 }
3447 else
3448 setalias(val);
3449 break;
3450
3451 case 'a': /* look N minutes for "@:@" in alias file */
3452 if (val[0] == '\0')
3453 SafeAlias = 5 MINUTES;
3454 else
3455 SafeAlias = convtime(val, 'm');
3456 break;
3457
3458 case 'B': /* substitution for blank character */
3459 SpaceSub = val[0];
3460 if (SpaceSub == '\0')
3461 SpaceSub = ' ';
3462 break;
3463
3464 case 'b': /* min blocks free on queue fs/max msg size */
3465 p = strchr(val, '/');
3466 if (p != NULL)
3467 {
3468 *p++ = '\0';
3469 MaxMessageSize = atol(p);
3470 }
3471 MinBlocksFree = atol(val);
3472 break;
3473
3474 case 'c': /* don't connect to "expensive" mailers */
3475 NoConnect = atobool(val);
3476 break;
3477
3478 case 'C': /* checkpoint every N addresses */
3479 if (safe || CheckpointInterval > atoi(val))
3480 CheckpointInterval = atoi(val);
3481 break;
3482
3483 case 'd': /* delivery mode */
3484 switch (*val)
3485 {
3486 case '\0':
3487 set_delivery_mode(SM_DELIVER, e);
3488 break;
3489
3490 case SM_QUEUE: /* queue only */
3491 case SM_DEFER: /* queue only and defer map lookups */
3492 case SM_DELIVER: /* do everything */
3493 case SM_FORK: /* fork after verification */
3494 #if _FFR_DM_ONE
3495 /* deliver first TA in background, then queue */
3496 case SM_DM_ONE:
3497 #endif
3498 #if _FFR_DMTRIGGER
3499 case SM_TRIGGER:
3500 #endif
3501 set_delivery_mode(*val, e);
3502 break;
3503
3504 #if _FFR_PROXY
3505 case SM_PROXY_REQ:
3506 set_delivery_mode(*val, e);
3507 break;
3508 #endif /* _FFR_PROXY */
3509
3510 default:
3511 syserr("Unknown delivery mode %c", *val);
3512 finis(false, true, EX_USAGE);
3513 }
3514 break;
3515
3516 case 'E': /* error message header/header file */
3517 if (*val != '\0')
3518 ErrMsgFile = newstr(val);
3519 break;
3520
3521 case 'e': /* set error processing mode */
3522 switch (*val)
3523 {
3524 case EM_QUIET: /* be silent about it */
3525 case EM_MAIL: /* mail back */
3526 case EM_BERKNET: /* do berknet error processing */
3527 case EM_WRITE: /* write back (or mail) */
3528 case EM_PRINT: /* print errors normally (default) */
3529 e->e_errormode = *val;
3530 break;
3531 }
3532 break;
3533
3534 case 'F': /* file mode */
3535 FileMode = atooct(val) & 0777;
3536 break;
3537
3538 case 'f': /* save Unix-style From lines on front */
3539 SaveFrom = atobool(val);
3540 break;
3541
3542 case 'G': /* match recipients against GECOS field */
3543 MatchGecos = atobool(val);
3544 break;
3545
3546 case 'g': /* default gid */
3547 g_opt:
3548 if (isascii(*val) && isdigit(*val))
3549 DefGid = atoi(val);
3550 else
3551 {
3552 register struct group *gr;
3553
3554 DefGid = -1;
3555 gr = getgrnam(val);
3556 if (gr == NULL)
3557 syserr("readcf: option %c: unknown group %s",
3558 opt, val);
3559 else
3560 DefGid = gr->gr_gid;
3561 }
3562 break;
3563
3564 case 'H': /* help file */
3565 if (val[0] == '\0')
3566 {
3567 SET_OPT_DEFAULT(HelpFile, "helpfile");
3568 }
3569 else
3570 {
3571 CANONIFY(val);
3572 HelpFile = newstr(val);
3573 }
3574 break;
3575
3576 case 'h': /* maximum hop count */
3577 MaxHopCount = atoi(val);
3578 break;
3579
3580 case 'I': /* use internet domain name server */
3581 #if NAMED_BIND
3582 for (p = val; *p != 0; )
3583 {
3584 bool clearmode;
3585 char *q;
3586 struct resolverflags *rfp;
3587
3588 while (*p == ' ')
3589 p++;
3590 if (*p == '\0')
3591 break;
3592 clearmode = false;
3593 if (*p == '-')
3594 clearmode = true;
3595 else if (*p != '+')
3596 p--;
3597 p++;
3598 q = p;
3599 while (*p != '\0' && !(SM_ISSPACE(*p)))
3600 p++;
3601 if (*p != '\0')
3602 *p++ = '\0';
3603 if (SM_STRCASEEQ(q, "HasWildcardMX"))
3604 {
3605 HasWildcardMX = !clearmode;
3606 continue;
3607 }
3608 if (SM_STRCASEEQ(q, "WorkAroundBrokenAAAA"))
3609 {
3610 WorkAroundBrokenAAAA = !clearmode;
3611 continue;
3612 }
3613 for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
3614 {
3615 if (SM_STRCASEEQ(q, rfp->rf_name))
3616 break;
3617 }
3618 if (rfp->rf_name == NULL)
3619 syserr("readcf: I option value %s unrecognized", q);
3620 else if (clearmode)
3621 _res.options &= ~rfp->rf_bits;
3622 else
3623 _res.options |= rfp->rf_bits;
3624 }
3625 if (tTd(8, 2))
3626 sm_dprintf("_res.options = %x, HasWildcardMX = %d\n",
3627 (unsigned int) _res.options, HasWildcardMX);
3628 #else /* NAMED_BIND */
3629 usrerr("name server (I option) specified but BIND not compiled in");
3630 #endif /* NAMED_BIND */
3631 break;
3632
3633 case 'i': /* ignore dot lines in message */
3634 IgnrDot = atobool(val);
3635 break;
3636
3637 case 'j': /* send errors in MIME (RFC 1341) format */
3638 SendMIMEErrors = atobool(val);
3639 break;
3640
3641 case 'J': /* .forward search path */
3642 CANONIFY(val);
3643 ForwardPath = newstr(val);
3644 break;
3645
3646 case 'k': /* connection cache size */
3647 MaxMciCache = atoi(val);
3648 if (MaxMciCache < 0)
3649 MaxMciCache = 0;
3650 break;
3651
3652 case 'K': /* connection cache timeout */
3653 MciCacheTimeout = convtime(val, 'm');
3654 break;
3655
3656 case 'l': /* use Errors-To: header */
3657 UseErrorsTo = atobool(val);
3658 break;
3659
3660 case 'L': /* log level */
3661 if (safe || LogLevel < atoi(val))
3662 LogLevel = atoi(val);
3663 break;
3664
3665 case 'M': /* define macro */
3666 sticky = false;
3667 i = macid_parse(val, &ep);
3668 if (i == 0)
3669 break;
3670 p = newstr(ep);
3671 if (!safe)
3672 cleanstrcpy(p, p, strlen(p) + 1);
3673 macdefine(&CurEnv->e_macro, A_TEMP, i, p);
3674 break;
3675
3676 case 'm': /* send to me too */
3677 MeToo = atobool(val);
3678 break;
3679
3680 case 'n': /* validate RHS in newaliases */
3681 CheckAliases = atobool(val);
3682 break;
3683
3684 /* 'N' available -- was "net name" */
3685
3686 case 'O': /* daemon options */
3687 if (!setdaemonoptions(val))
3688 syserr("too many daemons defined (%d max)", MAXDAEMONS);
3689 break;
3690
3691 case 'o': /* assume old style headers */
3692 if (atobool(val))
3693 CurEnv->e_flags |= EF_OLDSTYLE;
3694 else
3695 CurEnv->e_flags &= ~EF_OLDSTYLE;
3696 break;
3697
3698 case 'p': /* select privacy level */
3699 p = val;
3700 for (;;)
3701 {
3702 register struct prival *pv;
3703 extern struct prival PrivacyValues[];
3704
3705 while (isascii(*p) && (isspace(*p) || ispunct(*p)))
3706 p++;
3707 if (*p == '\0')
3708 break;
3709 val = p;
3710 while (isascii(*p) && isalnum(*p))
3711 p++;
3712 if (*p != '\0')
3713 *p++ = '\0';
3714
3715 for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
3716 {
3717 if (SM_STRCASEEQ(val, pv->pv_name))
3718 break;
3719 }
3720 if (pv->pv_name == NULL)
3721 syserr("readcf: Op line: %s unrecognized", val);
3722 else
3723 PrivacyFlags |= pv->pv_flag;
3724 }
3725 sticky = false;
3726 break;
3727
3728 case 'P': /* postmaster copy address for returned mail */
3729 PostMasterCopy = newstr(val);
3730 break;
3731
3732 case 'q': /* slope of queue only function */
3733 QueueFactor = atoi(val);
3734 break;
3735
3736 case 'Q': /* queue directory */
3737 if (val[0] == '\0')
3738 {
3739 QueueDir = "mqueue";
3740 }
3741 else
3742 {
3743 QueueDir = newstr(val);
3744 }
3745 if (RealUid != 0 && !safe)
3746 Warn_Q_option = true;
3747 break;
3748
3749 case 'R': /* don't prune routes */
3750 DontPruneRoutes = atobool(val);
3751 break;
3752
3753 case 'r': /* read timeout */
3754 if (subopt == NULL)
3755 inittimeouts(val, sticky);
3756 else
3757 settimeout(subopt, val, sticky);
3758 break;
3759
3760 case 'S': /* status file */
3761 if (val[0] == '\0')
3762 {
3763 SET_OPT_DEFAULT(StatFile, "statistics");
3764 }
3765 else
3766 {
3767 CANONIFY(val);
3768 StatFile = newstr(val);
3769 }
3770 break;
3771
3772 case 's': /* be super safe, even if expensive */
3773 if (tolower(*val) == 'i')
3774 SuperSafe = SAFE_INTERACTIVE;
3775 else if (tolower(*val) == 'p')
3776 #if MILTER
3777 SuperSafe = SAFE_REALLY_POSTMILTER;
3778 #else /* MILTER */
3779 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3780 "Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n");
3781 #endif /* MILTER */
3782 else
3783 SuperSafe = atobool(val) ? SAFE_REALLY : SAFE_NO;
3784 break;
3785
3786 case 'T': /* queue timeout */
3787 p = strchr(val, '/');
3788 if (p != NULL)
3789 {
3790 *p++ = '\0';
3791 settimeout("queuewarn", p, sticky);
3792 }
3793 settimeout("queuereturn", val, sticky);
3794 break;
3795
3796 case 't': /* time zone name */
3797 TimeZoneSpec = newstr(val);
3798 break;
3799
3800 case 'U': /* location of user database */
3801 UdbSpec = newstr(val);
3802 break;
3803
3804 case 'u': /* set default uid */
3805 for (p = val; *p != '\0'; p++)
3806 {
3807 #if _FFR_DOTTED_USERNAMES
3808 if (*p == '/' || *p == ':')
3809 #else
3810 if (*p == '.' || *p == '/' || *p == ':')
3811 #endif
3812 {
3813 *p++ = '\0';
3814 break;
3815 }
3816 }
3817 if (isascii(*val) && isdigit(*val))
3818 {
3819 DefUid = atoi(val);
3820 setdefuser();
3821 }
3822 else
3823 {
3824 register struct passwd *pw;
3825
3826 DefUid = -1;
3827 pw = sm_getpwnam(val);
3828 if (pw == NULL)
3829 {
3830 syserr("readcf: option u: unknown user %s", val);
3831 break;
3832 }
3833 else
3834 {
3835 DefUid = pw->pw_uid;
3836 DefGid = pw->pw_gid;
3837 DefUser = newstr(pw->pw_name);
3838 }
3839 }
3840
3841 #ifdef UID_MAX
3842 if (DefUid > UID_MAX)
3843 {
3844 syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored",
3845 (long)DefUid, (long)UID_MAX);
3846 break;
3847 }
3848 #endif /* UID_MAX */
3849
3850 /* handle the group if it is there */
3851 if (*p == '\0')
3852 break;
3853 val = p;
3854 goto g_opt;
3855
3856 case 'V': /* fallback MX host */
3857 if (val[0] != '\0')
3858 FallbackMX = newstr(val);
3859 break;
3860
3861 case 'v': /* run in verbose mode */
3862 Verbose = atobool(val) ? 1 : 0;
3863 break;
3864
3865 case 'w': /* if we are best MX, try host directly */
3866 TryNullMXList = atobool(val);
3867 break;
3868
3869 /* 'W' available -- was wizard password */
3870
3871 case 'x': /* load avg at which to auto-queue msgs */
3872 QueueLA = atoi(val);
3873 break;
3874
3875 case 'X': /* load avg at which to auto-reject connections */
3876 RefuseLA = atoi(val);
3877 break;
3878
3879 case O_DELAY_LA: /* load avg at which to delay connections */
3880 DelayLA = atoi(val);
3881 break;
3882
3883 case 'y': /* work recipient factor */
3884 WkRecipFact = atoi(val);
3885 break;
3886
3887 case 'Y': /* fork jobs during queue runs */
3888 ForkQueueRuns = atobool(val);
3889 break;
3890
3891 case 'z': /* work message class factor */
3892 WkClassFact = atoi(val);
3893 break;
3894
3895 case 'Z': /* work time factor */
3896 WkTimeFact = atoi(val);
3897 break;
3898
3899 #if _FFR_QUEUE_GROUP_SORTORDER
3900 /* coordinate this with makequeue() */
3901 #endif
3902 case O_QUEUESORTORD: /* queue sorting order */
3903 switch (*val)
3904 {
3905 case 'f': /* File Name */
3906 case 'F':
3907 QueueSortOrder = QSO_BYFILENAME;
3908 break;
3909
3910 case 'h': /* Host first */
3911 case 'H':
3912 QueueSortOrder = QSO_BYHOST;
3913 break;
3914
3915 case 'm': /* Modification time */
3916 case 'M':
3917 QueueSortOrder = QSO_BYMODTIME;
3918 break;
3919
3920 case 'p': /* Priority order */
3921 case 'P':
3922 QueueSortOrder = QSO_BYPRIORITY;
3923 break;
3924
3925 case 't': /* Submission time */
3926 case 'T':
3927 QueueSortOrder = QSO_BYTIME;
3928 break;
3929
3930 case 'r': /* Random */
3931 case 'R':
3932 QueueSortOrder = QSO_RANDOM;
3933 break;
3934
3935 #if _FFR_RHS
3936 case 's': /* Shuffled host name */
3937 case 'S':
3938 QueueSortOrder = QSO_BYSHUFFLE;
3939 break;
3940 #endif /* _FFR_RHS */
3941
3942 case 'n': /* none */
3943 case 'N':
3944 QueueSortOrder = QSO_NONE;
3945 break;
3946
3947 default:
3948 syserr("Invalid queue sort order \"%s\"", val);
3949 }
3950 break;
3951
3952 case O_HOSTSFILE: /* pathname of /etc/hosts file */
3953 CANONIFY(val);
3954 HostsFile = newstr(val);
3955 break;
3956
3957 case O_MQA: /* minimum queue age between deliveries */
3958 MinQueueAge = convtime(val, 'm');
3959 break;
3960
3961 case O_MAX_QUEUE_AGE:
3962 MaxQueueAge = convtime(val, 'm');
3963 break;
3964
3965 case O_DEFCHARSET: /* default character set for mimefying */
3966 DefaultCharSet = newstr(denlstring(val, true, true));
3967 break;
3968
3969 case O_SSFILE: /* service switch file */
3970 CANONIFY(val);
3971 ServiceSwitchFile = newstr(val);
3972 break;
3973
3974 case O_DIALDELAY: /* delay for dial-on-demand operation */
3975 DialDelay = convtime(val, 's');
3976 break;
3977
3978 case O_NORCPTACTION: /* what to do if no recipient */
3979 if (SM_STRCASEEQ(val, "none"))
3980 NoRecipientAction = NRA_NO_ACTION;
3981 else if (SM_STRCASEEQ(val, "add-to"))
3982 NoRecipientAction = NRA_ADD_TO;
3983 else if (SM_STRCASEEQ(val, "add-apparently-to"))
3984 NoRecipientAction = NRA_ADD_APPARENTLY_TO;
3985 else if (SM_STRCASEEQ(val, "add-bcc"))
3986 NoRecipientAction = NRA_ADD_BCC;
3987 else if (SM_STRCASEEQ(val, "add-to-undisclosed"))
3988 NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
3989 else
3990 syserr("Invalid NoRecipientAction: %s", val);
3991 break;
3992
3993 case O_SAFEFILEENV: /* chroot() environ for writing to files */
3994 if (*val == '\0')
3995 break;
3996
3997 /* strip trailing slashes */
3998 p = val + strlen(val) - 1;
3999 while (p >= val && *p == '/')
4000 *p-- = '\0';
4001
4002 if (*val == '\0')
4003 break;
4004
4005 SafeFileEnv = newstr(val);
4006 break;
4007
4008 case O_MAXMSGSIZE: /* maximum message size */
4009 MaxMessageSize = atol(val);
4010 break;
4011
4012 case O_COLONOKINADDR: /* old style handling of colon addresses */
4013 ColonOkInAddr = atobool(val);
4014 break;
4015
4016 case O_MAXQUEUERUN: /* max # of jobs in a single queue run */
4017 MaxQueueRun = atoi(val);
4018 break;
4019
4020 case O_MAXCHILDREN: /* max # of children of daemon */
4021 MaxChildren = atoi(val);
4022 break;
4023
4024 case O_MAXQUEUECHILDREN: /* max # of children of daemon */
4025 MaxQueueChildren = atoi(val);
4026 break;
4027
4028 case O_MAXRUNNERSPERQUEUE: /* max # runners in a queue group */
4029 MaxRunnersPerQueue = atoi(val);
4030 break;
4031
4032 case O_NICEQUEUERUN: /* nice queue runs */
4033 #if !HASNICE
4034 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4035 "Warning: NiceQueueRun set on system that doesn't support nice()\n");
4036 #endif
4037
4038 /* XXX do we want to check the range? > 0 ? */
4039 NiceQueueRun = atoi(val);
4040 break;
4041
4042 case O_SHMKEY: /* shared memory key */
4043 #if SM_CONF_SHM
4044 ShmKey = atol(val);
4045 #else /* SM_CONF_SHM */
4046 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4047 "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n",
4048 OPTNAME);
4049 #endif /* SM_CONF_SHM */
4050 break;
4051
4052 case O_SHMKEYFILE: /* shared memory key file */
4053 #if SM_CONF_SHM
4054 SET_STRING_EXP(ShmKeyFile);
4055 #else /* SM_CONF_SHM */
4056 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4057 "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n",
4058 OPTNAME);
4059 break;
4060 #endif /* SM_CONF_SHM */
4061
4062 #if _FFR_MAX_FORWARD_ENTRIES
4063 case O_MAXFORWARD: /* max # of forward entries */
4064 MaxForwardEntries = atoi(val);
4065 break;
4066 #endif
4067
4068 case O_KEEPCNAMES: /* don't expand CNAME records */
4069 DontExpandCnames = atobool(val);
4070 break;
4071
4072 case O_MUSTQUOTE: /* must quote these characters in phrases */
4073 (void) sm_strlcpy(buf, "@,;:\\()[]", sizeof(buf));
4074 if (strlen(val) < sizeof(buf) - 10)
4075 (void) sm_strlcat(buf, val, sizeof(buf));
4076 else
4077 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4078 "Warning: MustQuoteChars too long, ignored.\n");
4079 MustQuoteChars = newstr(buf);
4080 break;
4081
4082 case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */
4083 SmtpGreeting = newstr(munchstring(val, NULL, '\0'));
4084 break;
4085
4086 case O_UNIXFROM: /* UNIX From_ line (old $l macro) */
4087 UnixFromLine = newstr(munchstring(val, NULL, '\0'));
4088 break;
4089
4090 case O_OPCHARS: /* operator characters (old $o macro) */
4091 if (OperatorChars != NULL)
4092 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4093 "Warning: OperatorChars is being redefined.\n It should only be set before ruleset definitions.\n");
4094 OperatorChars = newstr(munchstring(val, NULL, '\0'));
4095 break;
4096
4097 case O_DONTINITGRPS: /* don't call initgroups(3) */
4098 DontInitGroups = atobool(val);
4099 break;
4100
4101 case O_SLFH: /* make sure from fits on one line */
4102 SingleLineFromHeader = atobool(val);
4103 break;
4104
4105 case O_ABH: /* allow HELO commands with syntax errors */
4106 AllowBogusHELO = atobool(val);
4107 break;
4108
4109 case O_CONNTHROT: /* connection rate throttle */
4110 ConnRateThrottle = atoi(val);
4111 break;
4112
4113 case O_UGW: /* group writable files are unsafe */
4114 if (!atobool(val))
4115 {
4116 setbitn(DBS_GROUPWRITABLEFORWARDFILESAFE,
4117 DontBlameSendmail);
4118 setbitn(DBS_GROUPWRITABLEINCLUDEFILESAFE,
4119 DontBlameSendmail);
4120 }
4121 break;
4122
4123 case O_DBLBOUNCE: /* address to which to send double bounces */
4124 DoubleBounceAddr = newstr(val);
4125 break;
4126
4127 case O_HSDIR: /* persistent host status directory */
4128 if (val[0] != '\0')
4129 {
4130 CANONIFY(val);
4131 HostStatDir = newstr(val);
4132 }
4133 break;
4134
4135 case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */
4136 SingleThreadDelivery = atobool(val);
4137 break;
4138
4139 case O_RUNASUSER: /* run bulk of code as this user */
4140 for (p = val; *p != '\0'; p++)
4141 {
4142 #if _FFR_DOTTED_USERNAMES
4143 if (*p == '/' || *p == ':')
4144 #else
4145 if (*p == '.' || *p == '/' || *p == ':')
4146 #endif
4147 {
4148 *p++ = '\0';
4149 break;
4150 }
4151 }
4152 if (isascii(*val) && isdigit(*val))
4153 {
4154 if (can_setuid)
4155 RunAsUid = atoi(val);
4156 }
4157 else
4158 {
4159 register struct passwd *pw;
4160
4161 pw = sm_getpwnam(val);
4162 if (pw == NULL)
4163 {
4164 syserr("readcf: option RunAsUser: unknown user %s", val);
4165 break;
4166 }
4167 else if (can_setuid)
4168 {
4169 if (*p == '\0')
4170 RunAsUserName = newstr(val);
4171 RunAsUid = pw->pw_uid;
4172 RunAsGid = pw->pw_gid;
4173 }
4174 else if (EffGid == pw->pw_gid)
4175 RunAsGid = pw->pw_gid;
4176 else if (UseMSP && *p == '\0')
4177 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4178 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n",
4179 (long) EffGid,
4180 (long) pw->pw_gid);
4181 }
4182 #ifdef UID_MAX
4183 if (RunAsUid > UID_MAX)
4184 {
4185 syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored",
4186 (long) RunAsUid, (long) UID_MAX);
4187 break;
4188 }
4189 #endif /* UID_MAX */
4190 if (*p != '\0')
4191 {
4192 if (isascii(*p) && isdigit(*p))
4193 {
4194 gid_t runasgid;
4195
4196 runasgid = (gid_t) atoi(p);
4197 if (can_setuid || EffGid == runasgid)
4198 RunAsGid = runasgid;
4199 else if (UseMSP)
4200 (void) sm_io_fprintf(smioout,
4201 SM_TIME_DEFAULT,
4202 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n",
4203 (long) EffGid,
4204 (long) runasgid);
4205 }
4206 else
4207 {
4208 register struct group *gr;
4209
4210 gr = getgrnam(p);
4211 if (gr == NULL)
4212 syserr("readcf: option RunAsUser: unknown group %s",
4213 p);
4214 else if (can_setuid || EffGid == gr->gr_gid)
4215 RunAsGid = gr->gr_gid;
4216 else if (UseMSP)
4217 (void) sm_io_fprintf(smioout,
4218 SM_TIME_DEFAULT,
4219 "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n",
4220 (long) EffGid,
4221 (long) gr->gr_gid);
4222 }
4223 }
4224 if (tTd(47, 5))
4225 sm_dprintf("readcf: RunAsUser = %d:%d\n",
4226 (int) RunAsUid, (int) RunAsGid);
4227 break;
4228
4229 case O_DSN_RRT:
4230 RrtImpliesDsn = atobool(val);
4231 break;
4232
4233 case O_PIDFILE:
4234 PSTRSET(PidFile, val);
4235 break;
4236
4237 case O_DONTBLAMESENDMAIL:
4238 p = val;
4239 for (;;)
4240 {
4241 register struct dbsval *dbs;
4242 extern struct dbsval DontBlameSendmailValues[];
4243
4244 while (isascii(*p) && (isspace(*p) || ispunct(*p)))
4245 p++;
4246 if (*p == '\0')
4247 break;
4248 val = p;
4249 while (isascii(*p) && isalnum(*p))
4250 p++;
4251 if (*p != '\0')
4252 *p++ = '\0';
4253
4254 for (dbs = DontBlameSendmailValues;
4255 dbs->dbs_name != NULL; dbs++)
4256 {
4257 if (SM_STRCASEEQ(val, dbs->dbs_name))
4258 break;
4259 }
4260 if (dbs->dbs_name == NULL)
4261 syserr("readcf: DontBlameSendmail option: %s unrecognized", val);
4262 else if (dbs->dbs_flag == DBS_SAFE)
4263 clrbitmap(DontBlameSendmail);
4264 else
4265 setbitn(dbs->dbs_flag, DontBlameSendmail);
4266 }
4267 sticky = false;
4268 break;
4269
4270 case O_DPI:
4271 if (SM_STRCASEEQ(val, "loopback"))
4272 DontProbeInterfaces = DPI_SKIPLOOPBACK;
4273 else if (atobool(val))
4274 DontProbeInterfaces = DPI_PROBENONE;
4275 else
4276 DontProbeInterfaces = DPI_PROBEALL;
4277 break;
4278
4279 case O_MAXRCPT:
4280 MaxRcptPerMsg = atoi(val);
4281 break;
4282
4283 case O_RCPTTHROT:
4284 BadRcptThrottle = atoi(val);
4285 break;
4286
4287 #if _FFR_RCPTTHROTDELAY
4288 case O_RCPTTHROTDELAY:
4289 BadRcptThrottleDelay = atoi(val);
4290 break;
4291 #endif
4292
4293 case O_DEADLETTER:
4294 CANONIFY(val);
4295 PSTRSET(DeadLetterDrop, val);
4296 break;
4297
4298 #if _FFR_DONTLOCKFILESFORREAD_OPTION
4299 case O_DONTLOCK:
4300 DontLockReadFiles = atobool(val);
4301 break;
4302 #endif
4303
4304 case O_MAXALIASRCSN:
4305 MaxAliasRecursion = atoi(val);
4306 break;
4307
4308 case O_CNCTONLYTO:
4309 /* XXX should probably use gethostbyname */
4310 #if NETINET || NETINET6
4311 i = 0;
4312 if ((subopt = strchr(val, '@')) != NULL)
4313 {
4314 *subopt = '\0';
4315 i = (int) strtoul(val, NULL, 0);
4316
4317 /* stricter checks? probably not useful. */
4318 if (i > USHRT_MAX)
4319 {
4320 syserr("readcf: option ConnectOnlyTo: invalid port %s",
4321 val);
4322 break;
4323 }
4324 val = subopt + 1;
4325 }
4326 ConnectOnlyTo.sa.sa_family = AF_UNSPEC;
4327 # if NETINET6
4328 if (anynet_pton(AF_INET6, val,
4329 &ConnectOnlyTo.sin6.sin6_addr) == 1)
4330 {
4331 ConnectOnlyTo.sa.sa_family = AF_INET6;
4332 if (i != 0)
4333 ConnectOnlyTo.sin6.sin6_port = htons(i);
4334 }
4335 else
4336 # endif /* NETINET6 */
4337 # if NETINET
4338 {
4339 ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val);
4340 if (ConnectOnlyTo.sin.sin_addr.s_addr != INADDR_NONE)
4341 ConnectOnlyTo.sa.sa_family = AF_INET;
4342 if (i != 0)
4343 ConnectOnlyTo.sin.sin_port = htons(i);
4344 }
4345
4346 # endif /* NETINET */
4347 if (ConnectOnlyTo.sa.sa_family == AF_UNSPEC)
4348 {
4349 syserr("readcf: option ConnectOnlyTo: invalid IP address %s",
4350 val);
4351 break;
4352 }
4353 #endif /* NETINET || NETINET6 */
4354 break;
4355
4356 case O_TRUSTUSER:
4357 #if !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING)
4358 if (!UseMSP)
4359 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4360 "readcf: option TrustedUser may cause problems on systems\n which do not support fchown() if UseMSP is not set.\n");
4361 #endif /* !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) */
4362 if (isascii(*val) && isdigit(*val))
4363 TrustedUid = atoi(val);
4364 else
4365 {
4366 register struct passwd *pw;
4367
4368 TrustedUid = 0;
4369 pw = sm_getpwnam(val);
4370 if (pw == NULL)
4371 {
4372 syserr("readcf: option TrustedUser: unknown user %s", val);
4373 break;
4374 }
4375 else
4376 TrustedUid = pw->pw_uid;
4377 }
4378
4379 #ifdef UID_MAX
4380 if (TrustedUid > UID_MAX)
4381 {
4382 syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)",
4383 (long) TrustedUid, (long) UID_MAX);
4384 TrustedUid = 0;
4385 }
4386 #endif /* UID_MAX */
4387 break;
4388
4389 case O_MAXMIMEHDRLEN:
4390 p = strchr(val, '/');
4391 if (p != NULL)
4392 *p++ = '\0';
4393 MaxMimeHeaderLength = atoi(val);
4394 if (p != NULL && *p != '\0')
4395 MaxMimeFieldLength = atoi(p);
4396 else
4397 MaxMimeFieldLength = MaxMimeHeaderLength / 2;
4398
4399 if (MaxMimeHeaderLength <= 0)
4400 MaxMimeHeaderLength = 0;
4401 else if (MaxMimeHeaderLength < 128)
4402 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4403 "Warning: MaxMimeHeaderLength: header length limit set lower than 128\n");
4404
4405 if (MaxMimeFieldLength <= 0)
4406 MaxMimeFieldLength = 0;
4407 else if (MaxMimeFieldLength < 40)
4408 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4409 "Warning: MaxMimeHeaderLength: field length limit set lower than 40\n");
4410
4411 /*
4412 ** Headers field values now include leading space, so let's
4413 ** adjust the values to be "backward compatible".
4414 */
4415
4416 if (MaxMimeHeaderLength > 0)
4417 MaxMimeHeaderLength++;
4418 if (MaxMimeFieldLength > 0)
4419 MaxMimeFieldLength++;
4420 break;
4421
4422 case O_CONTROLSOCKET:
4423 PSTRSET(ControlSocketName, val);
4424 break;
4425
4426 case O_MAXHDRSLEN:
4427 MaxHeadersLength = atoi(val);
4428
4429 if (MaxHeadersLength > 0 &&
4430 MaxHeadersLength < (MAXHDRSLEN / 2))
4431 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4432 "Warning: MaxHeadersLength: headers length limit set lower than %d\n",
4433 (MAXHDRSLEN / 2));
4434 break;
4435
4436 case O_PROCTITLEPREFIX:
4437 PSTRSET(ProcTitlePrefix, val);
4438 break;
4439
4440 #if SASL
4441 case O_SASLINFO:
4442 # if _FFR_ALLOW_SASLINFO
4443 /*
4444 ** Allow users to select their own authinfo file
4445 ** under certain circumstances, otherwise just ignore
4446 ** the option. If the option isn't ignored, several
4447 ** commands don't work very well, e.g., mailq.
4448 ** However, this is not a "perfect" solution.
4449 ** If mail is queued, the authentication info
4450 ** will not be used in subsequent delivery attempts.
4451 ** If we really want to support this, then it has
4452 ** to be stored in the queue file.
4453 */
4454 if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 &&
4455 RunAsUid != RealUid)
4456 break;
4457 # endif /* _FFR_ALLOW_SASLINFO */
4458 PSTRSET(SASLInfo, val);
4459 break;
4460
4461 case O_SASLMECH:
4462 if (AuthMechanisms != NULL)
4463 sm_free(AuthMechanisms); /* XXX */
4464 if (*val != '\0')
4465 AuthMechanisms = newstr(val);
4466 else
4467 AuthMechanisms = NULL;
4468 break;
4469
4470 case O_SASLREALM:
4471 if (AuthRealm != NULL)
4472 sm_free(AuthRealm);
4473 if (*val != '\0')
4474 AuthRealm = newstr(val);
4475 else
4476 AuthRealm = NULL;
4477 break;
4478
4479 case O_SASLOPTS:
4480 while (val != NULL && *val != '\0')
4481 {
4482 switch (*val)
4483 {
4484 case 'A':
4485 SASLOpts |= SASL_AUTH_AUTH;
4486 break;
4487
4488 case 'a':
4489 SASLOpts |= SASL_SEC_NOACTIVE;
4490 break;
4491
4492 case 'c':
4493 SASLOpts |= SASL_SEC_PASS_CREDENTIALS;
4494 break;
4495
4496 case 'd':
4497 SASLOpts |= SASL_SEC_NODICTIONARY;
4498 break;
4499
4500 case 'f':
4501 SASLOpts |= SASL_SEC_FORWARD_SECRECY;
4502 break;
4503
4504 # if SASL >= 20101
4505 case 'm':
4506 SASLOpts |= SASL_SEC_MUTUAL_AUTH;
4507 break;
4508 # endif /* SASL >= 20101 */
4509
4510 case 'p':
4511 SASLOpts |= SASL_SEC_NOPLAINTEXT;
4512 break;
4513
4514 case 'y':
4515 SASLOpts |= SASL_SEC_NOANONYMOUS;
4516 break;
4517
4518 case ' ': /* ignore */
4519 case '\t': /* ignore */
4520 case ',': /* ignore */
4521 break;
4522
4523 default:
4524 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4525 "Warning: Option: %s unknown parameter '%c'\n",
4526 OPTNAME,
4527 (isascii(*val) &&
4528 isprint(*val))
4529 ? *val : '?');
4530 break;
4531 }
4532 ++val;
4533 val = strpbrk(val, ", \t");
4534 if (val != NULL)
4535 ++val;
4536 }
4537 break;
4538
4539 case O_SASLBITS:
4540 MaxSLBits = atoi(val);
4541 break;
4542
4543 #else /* SASL */
4544 case O_SASLINFO:
4545 case O_SASLMECH:
4546 case O_SASLREALM:
4547 case O_SASLOPTS:
4548 case O_SASLBITS:
4549 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4550 "Warning: Option: %s requires SASL support (-DSASL)\n",
4551 OPTNAME);
4552 break;
4553 #endif /* SASL */
4554
4555 #if STARTTLS
4556 case O_TLSFB2CLEAR:
4557 TLSFallbacktoClear = atobool(val);
4558 break;
4559 case O_SRVCERTFILE:
4560 SET_STRING_EXP(SrvCertFile);
4561 case O_SRVKEYFILE:
4562 SET_STRING_EXP(SrvKeyFile);
4563 case O_CLTCERTFILE:
4564 SET_STRING_EXP(CltCertFile);
4565 case O_CLTKEYFILE:
4566 SET_STRING_EXP(CltKeyFile);
4567 case O_CACERTFILE:
4568 SET_STRING_EXP(CACertFile);
4569 case O_CACERTPATH:
4570 SET_STRING_EXP(CACertPath);
4571 # if _FFR_CLIENTCA
4572 case O_CLTCACERTFILE:
4573 SET_STRING_EXP(CltCACertFile);
4574 case O_CLTCACERTPATH:
4575 SET_STRING_EXP(CltCACertPath);
4576 # endif
4577 case O_DHPARAMS:
4578 SET_STRING_EXP(DHParams);
4579 case O_CIPHERLIST:
4580 SET_STRING_EXP(CipherList);
4581 # if MTA_HAVE_TLSv1_3
4582 case O_CIPHERSUITES:
4583 SET_STRING_EXP(CipherSuites);
4584 # endif
4585 case O_DIG_ALG:
4586 SET_STRING_EXP(CertFingerprintAlgorithm);
4587 # if !defined(OPENSSL_NO_ENGINE)
4588 case O_SSLENGINEPATH:
4589 SET_STRING_EXP(SSLEnginePath);
4590 case O_SSLENGINE:
4591 newval = sm_pstrdup_x(val);
4592 if (SSLEngine != NULL)
4593 sm_free(SSLEngine);
4594 SSLEngine = newval;
4595
4596 /*
4597 ** Which engines need to be initialized before fork()?
4598 ** XXX hack, should be an option?
4599 */
4600
4601 if (strcmp(SSLEngine, "chil") == 0)
4602 SSLEngineprefork = true;
4603 break;
4604 # else /* !defined(OPENSSL_NO_ENGINE) */
4605 case O_SSLENGINEPATH:
4606 case O_SSLENGINE:
4607 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4608 "Warning: Option: %s ignored -- not supported: OPENSSL_NO_ENGINE\n",
4609 OPTNAME);
4610 /* XXX fail? */
4611 break;
4612 # endif /* !defined(OPENSSL_NO_ENGINE) */
4613 case O_SRV_SSL_OPTIONS:
4614 pssloptions = &Srv_SSL_Options;
4615 case O_CLT_SSL_OPTIONS:
4616 if (pssloptions == NULL)
4617 pssloptions = &Clt_SSL_Options;
4618 (void) readssloptions(o->o_name, val, pssloptions, '\0');
4619 if (tTd(37, 8))
4620 sm_dprintf("ssloptions=%#lx\n", *pssloptions);
4621
4622 pssloptions = NULL;
4623 break;
4624
4625 case O_CRLFILE:
4626 SET_STRING_EXP(CRLFile);
4627 break;
4628
4629 case O_CRLPATH:
4630 SET_STRING_EXP(CRLPath);
4631 break;
4632
4633 /*
4634 ** XXX How about options per daemon/client instead of globally?
4635 ** This doesn't work well for some options, e.g., no server cert,
4636 ** but fine for others.
4637 **
4638 ** XXX Some people may want different certs per server.
4639 **
4640 ** See also srvfeatures()
4641 */
4642
4643 case O_TLS_SRV_OPTS:
4644 while (val != NULL && *val != '\0')
4645 {
4646 switch (*val)
4647 {
4648 case 'V':
4649 TLS_Srv_Opts |= TLS_I_NO_VRFY;
4650 break;
4651 /*
4652 ** Server without a cert? That works only if
4653 ** AnonDH is enabled as cipher, which is not in the
4654 ** default list. Hence the CipherList option must
4655 ** be available. Moreover: which clients support this
4656 ** besides sendmail with this setting?
4657 */
4658
4659 case 'C':
4660 TLS_Srv_Opts &= ~TLS_I_SRV_CERT;
4661 break;
4662 case ' ': /* ignore */
4663 case '\t': /* ignore */
4664 case ',': /* ignore */
4665 break;
4666 default:
4667 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4668 "Warning: Option: %s unknown parameter '%c'\n",
4669 OPTNAME,
4670 (isascii(*val) &&
4671 isprint(*val))
4672 ? *val : '?');
4673 break;
4674 }
4675 ++val;
4676 val = strpbrk(val, ", \t");
4677 if (val != NULL)
4678 ++val;
4679 }
4680 break;
4681
4682 case O_RANDFILE:
4683 PSTRSET(RandFile, val);
4684 break;
4685
4686 #else /* STARTTLS */
4687 case O_SRVCERTFILE:
4688 case O_SRVKEYFILE:
4689 case O_CLTCERTFILE:
4690 case O_CLTKEYFILE:
4691 case O_CACERTFILE:
4692 case O_CACERTPATH:
4693 # if _FFR_CLIENTCA
4694 case O_CLTCACERTFILE:
4695 case O_CLTCACERTPATH:
4696 # endif
4697 case O_DHPARAMS:
4698 case O_SRV_SSL_OPTIONS:
4699 case O_CLT_SSL_OPTIONS:
4700 case O_CIPHERLIST:
4701 case O_DIG_ALG:
4702 case O_CRLFILE:
4703 case O_CRLPATH:
4704 case O_RANDFILE:
4705 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4706 "Warning: Option: %s requires TLS support\n",
4707 OPTNAME);
4708 break;
4709
4710 #endif /* STARTTLS */
4711 #if STARTTLS && _FFR_FIPSMODE
4712 case O_FIPSMODE:
4713 FipsMode = atobool(val);
4714 break;
4715 #endif
4716
4717 case O_CLIENTPORT:
4718 setclientoptions(val);
4719 break;
4720
4721 case O_DF_BUFSIZE:
4722 DataFileBufferSize = atoi(val);
4723 break;
4724
4725 case O_XF_BUFSIZE:
4726 XscriptFileBufferSize = atoi(val);
4727 break;
4728
4729 case O_LDAPDEFAULTSPEC:
4730 #if LDAPMAP
4731 ldapmap_set_defaults(val);
4732 #else /* LDAPMAP */
4733 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4734 "Warning: Option: %s requires LDAP support (-DLDAPMAP)\n",
4735 OPTNAME);
4736 #endif /* LDAPMAP */
4737 break;
4738
4739 case O_INPUTMILTER:
4740 #if MILTER
4741 InputFilterList = newstr(val);
4742 #else /* MILTER */
4743 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4744 "Warning: Option: %s requires Milter support (-DMILTER)\n",
4745 OPTNAME);
4746 #endif /* MILTER */
4747 break;
4748
4749 case O_MILTER:
4750 #if MILTER
4751 milter_set_option(subopt, val, sticky);
4752 #else /* MILTER */
4753 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4754 "Warning: Option: %s requires Milter support (-DMILTER)\n",
4755 OPTNAME);
4756 #endif /* MILTER */
4757 break;
4758
4759 case O_QUEUE_FILE_MODE: /* queue file mode */
4760 QueueFileMode = atooct(val) & 0777;
4761 break;
4762
4763 case O_DLVR_MIN: /* deliver by minimum time */
4764 DeliverByMin = convtime(val, 's');
4765 break;
4766
4767 /* modifiers {daemon_flags} for direct submissions */
4768 case O_DIRECTSUBMODIFIERS:
4769 {
4770 BITMAP256 m; /* ignored */
4771 extern ENVELOPE BlankEnvelope;
4772
4773 macdefine(&BlankEnvelope.e_macro, A_PERM,
4774 macid("{daemon_flags}"),
4775 getmodifiers(val, m));
4776 }
4777 break;
4778
4779 case O_FASTSPLIT:
4780 FastSplit = atoi(val);
4781 break;
4782
4783 case O_MBDB:
4784 Mbdb = newstr(val);
4785 break;
4786
4787 case O_MSQ:
4788 UseMSP = atobool(val);
4789 break;
4790
4791 case O_SOFTBOUNCE:
4792 SoftBounce = atobool(val);
4793 break;
4794
4795 case O_REJECTLOGINTERVAL: /* time btwn log msgs while refusing */
4796 RejectLogInterval = convtime(val, 'h');
4797 break;
4798
4799 case O_REQUIRES_DIR_FSYNC:
4800 #if REQUIRES_DIR_FSYNC
4801 RequiresDirfsync = atobool(val);
4802 #else
4803 /* silently ignored... required for cf file option */
4804 #endif
4805 break;
4806
4807 case O_CONNECTION_RATE_WINDOW_SIZE:
4808 ConnectionRateWindowSize = convtime(val, 's');
4809 break;
4810
4811 case O_FALLBACKSMARTHOST: /* fallback smart host */
4812 if (val[0] != '\0')
4813 FallbackSmartHost = newstr(val);
4814 break;
4815
4816 case O_HELONAME:
4817 HeloName = newstr(val);
4818 break;
4819
4820 #if _FFR_MEMSTAT
4821 case O_REFUSELOWMEM:
4822 RefuseLowMem = atoi(val);
4823 break;
4824 case O_QUEUELOWMEM:
4825 QueueLowMem = atoi(val);
4826 break;
4827 case O_MEMRESOURCE:
4828 MemoryResource = newstr(val);
4829 break;
4830 #endif /* _FFR_MEMSTAT */
4831
4832 case O_MAXNOOPCOMMANDS:
4833 MaxNOOPCommands = atoi(val);
4834 break;
4835
4836 #if _FFR_MSG_ACCEPT
4837 case O_MSG_ACCEPT:
4838 MessageAccept = newstr(val);
4839 break;
4840 #endif
4841
4842 #if _FFR_QUEUE_RUN_PARANOIA
4843 case O_CHK_Q_RUNNERS:
4844 CheckQueueRunners = atoi(val);
4845 break;
4846 #endif
4847
4848 #if _FFR_EIGHT_BIT_ADDR_OK
4849 case O_EIGHT_BIT_ADDR_OK:
4850 EightBitAddrOK = atobool(val);
4851 break;
4852 #endif
4853
4854 #if _FFR_ADDR_TYPE_MODES
4855 case O_ADDR_TYPE_MODES:
4856 AddrTypeModes = atobool(val);
4857 break;
4858 #endif
4859
4860 #if _FFR_BADRCPT_SHUTDOWN
4861 case O_RCPTSHUTD:
4862 BadRcptShutdown = atoi(val);
4863 break;
4864
4865 case O_RCPTSHUTDG:
4866 BadRcptShutdownGood = atoi(val);
4867 break;
4868 #endif /* _FFR_BADRCPT_SHUTDOWN */
4869
4870 #if _FFR_REJECT_NUL_BYTE
4871 case O_REJECTNUL:
4872 RejectNUL = atobool(val);
4873 break;
4874 #endif
4875
4876 #if _FFR_BOUNCE_QUEUE
4877 case O_BOUNCEQUEUE:
4878 bouncequeue = newstr(val);
4879 break;
4880 #endif
4881
4882 #if _FFR_ADD_BCC
4883 case O_ADDBCC:
4884 AddBcc = atobool(val);
4885 break;
4886 #endif
4887 case O_USECOMPRESSEDIPV6ADDRESSES:
4888 UseCompressedIPv6Addresses = atobool(val);
4889 break;
4890
4891 #if DNSSEC_TEST || _FFR_NAMESERVER
4892 case O_NSPORTIP:
4893 nsportip(val);
4894 break;
4895 case O_NSSRCHLIST:
4896 NameSearchList = sm_strdup(val);
4897 break;
4898 #endif
4899
4900 #if DANE
4901 case O_DANE:
4902 if (SM_STRCASEEQ(val, "always"))
4903 Dane = DANE_ALWAYS;
4904 else
4905 Dane = atobool(val) ? DANE_SECURE : DANE_NEVER;
4906 break;
4907 #endif
4908
4909 #if _FFR_BLANKENV_MACV
4910 case O_HACKS:
4911 Hacks = (int) strtol(val, NULL, 0);
4912 break;
4913 #endif
4914
4915 #if _FFR_KEEPBCC
4916 case O_KEEPBCC:
4917 KeepBcc = atobool(val);
4918 break;
4919 #endif
4920
4921 #if _FFR_TLS_ALTNAMES
4922 case O_CHECKALTNAMES:
4923 SetCertAltnames = atobool(val);
4924 break;
4925 #endif
4926 case O_SMTPUTF8:
4927 #if USE_EAI
4928 /* hack for testing */
4929 if (isascii(*val) && isdigit(*val))
4930 SMTP_UTF8 = (int) strtol(val, NULL, 0);
4931 else
4932 SMTP_UTF8 = atobool(val);
4933 #else
4934 if (atobool(val))
4935 syserr("readcf: option: %s set but no USE_EAI support",
4936 OPTNAME);
4937 else
4938 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4939 "Warning: Option: %s requires USE_EAI support\n",
4940 OPTNAME);
4941 #endif
4942 break;
4943 #if _FFR_MTA_STS
4944 case O_MTASTS:
4945 MTASTS = atobool(val);
4946 break;
4947 #endif
4948
4949 default:
4950 if (tTd(37, 1))
4951 {
4952 if (isascii(opt) && isprint(opt))
4953 sm_dprintf("Warning: option %c unknown\n", opt);
4954 else
4955 sm_dprintf("Warning: option 0x%x unknown\n", opt);
4956 }
4957 break;
4958 }
4959
4960 /*
4961 ** Options with suboptions are responsible for taking care
4962 ** of sticky-ness (e.g., that a command line setting is kept
4963 ** when reading in the sendmail.cf file). This has to be done
4964 ** when the suboptions are parsed since each suboption must be
4965 ** sticky, not the root option.
4966 */
4967
4968 if (sticky && !bitset(OI_SUBOPT, o->o_flags))
4969 setbitn(opt, StickyOpt);
4970 }
4971 /*
4972 ** SETCLASS -- set a string into a class
4973 **
4974 ** Parameters:
4975 ** class -- the class to put the string in.
4976 ** str -- the string to enter
4977 **
4978 ** Returns:
4979 ** none.
4980 **
4981 ** Side Effects:
4982 ** puts the word into the symbol table.
4983 */
4984
4985 void
setclass(class,str)4986 setclass(class, str)
4987 int class;
4988 char *str;
4989 {
4990 register STAB *s;
4991
4992 if ((str[0] & 0377) == MATCHCLASS)
4993 {
4994 int mid;
4995
4996 str++;
4997 mid = macid(str);
4998 if (mid == 0)
4999 return;
5000
5001 if (tTd(37, 8))
5002 sm_dprintf("setclass(%s, $=%s)\n",
5003 macname(class), macname(mid));
5004 copy_class(mid, class);
5005 }
5006 else
5007 {
5008 if (tTd(37, 8))
5009 sm_dprintf("setclass(%s, %s)\n", macname(class), str);
5010
5011 s = stab(str, ST_CLASS, ST_ENTER);
5012 setbitn(bitidx(class), s->s_class);
5013 }
5014 }
5015
5016 #if _FFR_CLASS_RM_ENTRY
5017 /*
5018 ** CLASSRMENTRY -- remove a string from a class
5019 **
5020 ** Parameters:
5021 ** class -- the class from which to remove the string.
5022 ** str -- the string to remove
5023 **
5024 ** Returns:
5025 ** none.
5026 **
5027 ** Side Effects:
5028 ** removes the string from the class (if it was in there).
5029 */
5030
5031 static void
classrmentry(class,str)5032 classrmentry(class, str)
5033 int class;
5034 char *str;
5035 {
5036 STAB *s;
5037
5038 s = stab(str, ST_CLASS, ST_FIND);
5039 if (NULL == s /* || ST_CLASS != s->s_symtype */)
5040 {
5041 if (tTd(37, 8))
5042 sm_dprintf("classrmentry: entry=%s not in class %s\n", str, macname(class));
5043 return;
5044 }
5045 clrbitn(bitidx(class), s->s_class);
5046 if (tTd(37, 8))
5047 sm_dprintf("classrmentry(%s, %s)=%d\n", macname(class), str, bitnset(bitidx(class), s->s_class));
5048 }
5049 #endif /* _FFR_CLASS_RM_ENTRY */
5050
5051 /*
5052 ** MAKEMAPENTRY -- create a map entry
5053 **
5054 ** Parameters:
5055 ** line -- the config file line
5056 **
5057 ** Returns:
5058 ** A pointer to the map that has been created.
5059 ** NULL if there was a syntax error.
5060 **
5061 ** Side Effects:
5062 ** Enters the map into the dictionary.
5063 */
5064
5065 MAP *
makemapentry(line)5066 makemapentry(line)
5067 char *line;
5068 {
5069 register char *p;
5070 char *mapname;
5071 char *classname;
5072 register STAB *s;
5073 STAB *class;
5074
5075 for (p = line; SM_ISSPACE(*p); p++)
5076 continue;
5077 if (!(isascii(*p) && isalnum(*p)))
5078 {
5079 syserr("readcf: config K line: no map name");
5080 return NULL;
5081 }
5082
5083 mapname = p;
5084 while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.')
5085 continue;
5086 if (*p != '\0')
5087 *p++ = '\0';
5088 while (SM_ISSPACE(*p))
5089 p++;
5090 if (!(isascii(*p) && isalnum(*p)))
5091 {
5092 syserr("readcf: config K line, map %s: no map class", mapname);
5093 return NULL;
5094 }
5095 classname = p;
5096 while (isascii(*++p) && isalnum(*p))
5097 continue;
5098 if (*p != '\0')
5099 *p++ = '\0';
5100 while (SM_ISSPACE(*p))
5101 p++;
5102
5103 /* look up the class */
5104 class = stab(classname, ST_MAPCLASS, ST_FIND);
5105 if (class == NULL)
5106 {
5107 syserr("readcf: map %s: class %s not available", mapname,
5108 classname);
5109 return NULL;
5110 }
5111
5112 /* enter the map */
5113 s = stab(mapname, ST_MAP, ST_ENTER);
5114 s->s_map.map_class = &class->s_mapclass;
5115 s->s_map.map_mname = newstr(mapname);
5116
5117 if (class->s_mapclass.map_parse(&s->s_map, p))
5118 s->s_map.map_mflags |= MF_VALID;
5119
5120 if (tTd(37, 5))
5121 {
5122 sm_dprintf("map %s, class %s, flags %lx, file %s,\n",
5123 s->s_map.map_mname, s->s_map.map_class->map_cname,
5124 s->s_map.map_mflags, s->s_map.map_file);
5125 sm_dprintf("\tapp %s, domain %s, rebuild %s\n",
5126 s->s_map.map_app, s->s_map.map_domain,
5127 s->s_map.map_rebuild);
5128 }
5129 return &s->s_map;
5130 }
5131 /*
5132 ** STRTORWSET -- convert string to rewriting set number
5133 **
5134 ** Parameters:
5135 ** p -- the pointer to the string to decode.
5136 ** endp -- if set, store the trailing delimiter here.
5137 ** stabmode -- ST_ENTER to create this entry, ST_FIND if
5138 ** it must already exist.
5139 **
5140 ** Returns:
5141 ** The appropriate ruleset number.
5142 ** -1 if it is not valid (error already printed)
5143 */
5144
5145 int
strtorwset(p,endp,stabmode)5146 strtorwset(p, endp, stabmode)
5147 char *p;
5148 char **endp;
5149 int stabmode;
5150 {
5151 int ruleset;
5152 static int nextruleset = MAXRWSETS;
5153
5154 while (SM_ISSPACE(*p))
5155 p++;
5156 if (!isascii(*p))
5157 {
5158 syserr("invalid ruleset name: \"%.20s\"", p);
5159 return -1;
5160 }
5161 if (isdigit(*p))
5162 {
5163 ruleset = strtol(p, endp, 10);
5164 if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
5165 {
5166 syserr("bad ruleset %d (%d max)",
5167 ruleset, MAXRWSETS / 2);
5168 ruleset = -1;
5169 }
5170 }
5171 else
5172 {
5173 STAB *s;
5174 char delim;
5175 char *q = NULL;
5176
5177 q = p;
5178 while (*p != '\0' && isascii(*p) && (isalnum(*p) || *p == '_'))
5179 p++;
5180 if (q == p || !(isascii(*q) && isalpha(*q)))
5181 {
5182 /* no valid characters */
5183 syserr("invalid ruleset name: \"%.20s\"", q);
5184 return -1;
5185 }
5186 while (SM_ISSPACE(*p))
5187 *p++ = '\0';
5188 delim = *p;
5189 if (delim != '\0')
5190 *p = '\0';
5191 s = stab(q, ST_RULESET, stabmode);
5192 if (delim != '\0')
5193 *p = delim;
5194
5195 if (s == NULL)
5196 return -1;
5197
5198 if (stabmode == ST_ENTER && delim == '=')
5199 {
5200 while (isascii(*++p) && isspace(*p))
5201 continue;
5202 if (!(isascii(*p) && isdigit(*p)))
5203 {
5204 syserr("bad ruleset definition \"%s\" (number required after `=')", q);
5205 ruleset = -1;
5206 }
5207 else
5208 {
5209 ruleset = strtol(p, endp, 10);
5210 if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
5211 {
5212 syserr("bad ruleset number %d in \"%s\" (%d max)",
5213 ruleset, q, MAXRWSETS / 2);
5214 ruleset = -1;
5215 }
5216 }
5217 }
5218 else
5219 {
5220 if (endp != NULL)
5221 *endp = p;
5222 if (s->s_ruleset >= 0)
5223 ruleset = s->s_ruleset;
5224 else if ((ruleset = --nextruleset) < MAXRWSETS / 2)
5225 {
5226 syserr("%s: too many named rulesets (%d max)",
5227 q, MAXRWSETS / 2);
5228 ruleset = -1;
5229 }
5230 }
5231 if (s->s_ruleset >= 0 &&
5232 ruleset >= 0 &&
5233 ruleset != s->s_ruleset)
5234 {
5235 syserr("%s: ruleset changed value (old %d, new %d)",
5236 q, s->s_ruleset, ruleset);
5237 ruleset = s->s_ruleset;
5238 }
5239 else if (ruleset >= 0)
5240 {
5241 s->s_ruleset = ruleset;
5242 }
5243 if (stabmode == ST_ENTER && ruleset >= 0)
5244 {
5245 char *h = NULL;
5246
5247 if (RuleSetNames[ruleset] != NULL)
5248 sm_free(RuleSetNames[ruleset]); /* XXX */
5249 if (delim != '\0' && (h = strchr(q, delim)) != NULL)
5250 *h = '\0';
5251 RuleSetNames[ruleset] = newstr(q);
5252 if (delim == '/' && h != NULL)
5253 *h = delim; /* put back delim */
5254 }
5255 }
5256 return ruleset;
5257 }
5258 /*
5259 ** SETTIMEOUT -- set an individual timeout
5260 **
5261 ** Parameters:
5262 ** name -- the name of the timeout.
5263 ** val -- the value of the timeout.
5264 ** sticky -- if set, don't let other setoptions override
5265 ** this value.
5266 **
5267 ** Returns:
5268 ** none.
5269 */
5270
5271 /* set if Timeout sub-option is stuck */
5272 static BITMAP256 StickyTimeoutOpt;
5273
5274 static struct timeoutinfo
5275 {
5276 char *to_name; /* long name of timeout */
5277 unsigned char to_code; /* code for option */
5278 } TimeOutTab[] =
5279 {
5280 #define TO_INITIAL 0x01
5281 { "initial", TO_INITIAL },
5282 #define TO_MAIL 0x02
5283 { "mail", TO_MAIL },
5284 #define TO_RCPT 0x03
5285 { "rcpt", TO_RCPT },
5286 #define TO_DATAINIT 0x04
5287 { "datainit", TO_DATAINIT },
5288 #define TO_DATABLOCK 0x05
5289 { "datablock", TO_DATABLOCK },
5290 #define TO_DATAFINAL 0x06
5291 { "datafinal", TO_DATAFINAL },
5292 #define TO_COMMAND 0x07
5293 { "command", TO_COMMAND },
5294 #define TO_RSET 0x08
5295 { "rset", TO_RSET },
5296 #define TO_HELO 0x09
5297 { "helo", TO_HELO },
5298 #define TO_QUIT 0x0A
5299 { "quit", TO_QUIT },
5300 #define TO_MISC 0x0B
5301 { "misc", TO_MISC },
5302 #define TO_IDENT 0x0C
5303 { "ident", TO_IDENT },
5304 #define TO_FILEOPEN 0x0D
5305 { "fileopen", TO_FILEOPEN },
5306 #define TO_CONNECT 0x0E
5307 { "connect", TO_CONNECT },
5308 #define TO_ICONNECT 0x0F
5309 { "iconnect", TO_ICONNECT },
5310 #define TO_QUEUEWARN 0x10
5311 { "queuewarn", TO_QUEUEWARN },
5312 { "queuewarn.*", TO_QUEUEWARN },
5313 #define TO_QUEUEWARN_NORMAL 0x11
5314 { "queuewarn.normal", TO_QUEUEWARN_NORMAL },
5315 #define TO_QUEUEWARN_URGENT 0x12
5316 { "queuewarn.urgent", TO_QUEUEWARN_URGENT },
5317 #define TO_QUEUEWARN_NON_URGENT 0x13
5318 { "queuewarn.non-urgent", TO_QUEUEWARN_NON_URGENT },
5319 #define TO_QUEUERETURN 0x14
5320 { "queuereturn", TO_QUEUERETURN },
5321 { "queuereturn.*", TO_QUEUERETURN },
5322 #define TO_QUEUERETURN_NORMAL 0x15
5323 { "queuereturn.normal", TO_QUEUERETURN_NORMAL },
5324 #define TO_QUEUERETURN_URGENT 0x16
5325 { "queuereturn.urgent", TO_QUEUERETURN_URGENT },
5326 #define TO_QUEUERETURN_NON_URGENT 0x17
5327 { "queuereturn.non-urgent", TO_QUEUERETURN_NON_URGENT },
5328 #define TO_HOSTSTATUS 0x18
5329 { "hoststatus", TO_HOSTSTATUS },
5330 #define TO_RESOLVER_RETRANS 0x19
5331 { "resolver.retrans", TO_RESOLVER_RETRANS },
5332 #define TO_RESOLVER_RETRANS_NORMAL 0x1A
5333 { "resolver.retrans.normal", TO_RESOLVER_RETRANS_NORMAL },
5334 #define TO_RESOLVER_RETRANS_FIRST 0x1B
5335 { "resolver.retrans.first", TO_RESOLVER_RETRANS_FIRST },
5336 #define TO_RESOLVER_RETRY 0x1C
5337 { "resolver.retry", TO_RESOLVER_RETRY },
5338 #define TO_RESOLVER_RETRY_NORMAL 0x1D
5339 { "resolver.retry.normal", TO_RESOLVER_RETRY_NORMAL },
5340 #define TO_RESOLVER_RETRY_FIRST 0x1E
5341 { "resolver.retry.first", TO_RESOLVER_RETRY_FIRST },
5342 #define TO_CONTROL 0x1F
5343 { "control", TO_CONTROL },
5344 #define TO_LHLO 0x20
5345 { "lhlo", TO_LHLO },
5346 #define TO_AUTH 0x21
5347 { "auth", TO_AUTH },
5348 #define TO_STARTTLS 0x22
5349 { "starttls", TO_STARTTLS },
5350 #define TO_ACONNECT 0x23
5351 { "aconnect", TO_ACONNECT },
5352 #define TO_QUEUEWARN_DSN 0x24
5353 { "queuewarn.dsn", TO_QUEUEWARN_DSN },
5354 #define TO_QUEUERETURN_DSN 0x25
5355 { "queuereturn.dsn", TO_QUEUERETURN_DSN },
5356 { NULL, 0 },
5357 };
5358
5359 static void
settimeout(name,val,sticky)5360 settimeout(name, val, sticky)
5361 char *name;
5362 char *val;
5363 bool sticky;
5364 {
5365 register struct timeoutinfo *to;
5366 int i, addopts;
5367 time_t toval;
5368
5369 if (tTd(37, 2))
5370 sm_dprintf("settimeout(%s = %s)", name, val);
5371
5372 for (to = TimeOutTab; to->to_name != NULL; to++)
5373 {
5374 if (SM_STRCASEEQ(to->to_name, name))
5375 break;
5376 }
5377
5378 if (to->to_name == NULL)
5379 {
5380 errno = 0; /* avoid bogus error text */
5381 syserr("settimeout: invalid timeout %s", name);
5382 return;
5383 }
5384
5385 /*
5386 ** See if this option is preset for us.
5387 */
5388
5389 if (!sticky && bitnset(to->to_code, StickyTimeoutOpt))
5390 {
5391 if (tTd(37, 2))
5392 sm_dprintf(" (ignored)\n");
5393 return;
5394 }
5395
5396 if (tTd(37, 2))
5397 sm_dprintf("\n");
5398
5399 toval = convtime(val, 'm');
5400 addopts = 0;
5401
5402 switch (to->to_code)
5403 {
5404 case TO_INITIAL:
5405 TimeOuts.to_initial = toval;
5406 break;
5407
5408 case TO_MAIL:
5409 TimeOuts.to_mail = toval;
5410 break;
5411
5412 case TO_RCPT:
5413 TimeOuts.to_rcpt = toval;
5414 break;
5415
5416 case TO_DATAINIT:
5417 TimeOuts.to_datainit = toval;
5418 break;
5419
5420 case TO_DATABLOCK:
5421 TimeOuts.to_datablock = toval;
5422 break;
5423
5424 case TO_DATAFINAL:
5425 TimeOuts.to_datafinal = toval;
5426 break;
5427
5428 case TO_COMMAND:
5429 TimeOuts.to_nextcommand = toval;
5430 break;
5431
5432 case TO_RSET:
5433 TimeOuts.to_rset = toval;
5434 break;
5435
5436 case TO_HELO:
5437 TimeOuts.to_helo = toval;
5438 break;
5439
5440 case TO_QUIT:
5441 TimeOuts.to_quit = toval;
5442 break;
5443
5444 case TO_MISC:
5445 TimeOuts.to_miscshort = toval;
5446 break;
5447
5448 case TO_IDENT:
5449 TimeOuts.to_ident = toval;
5450 break;
5451
5452 case TO_FILEOPEN:
5453 TimeOuts.to_fileopen = toval;
5454 break;
5455
5456 case TO_CONNECT:
5457 TimeOuts.to_connect = toval;
5458 break;
5459
5460 case TO_ICONNECT:
5461 TimeOuts.to_iconnect = toval;
5462 break;
5463
5464 case TO_ACONNECT:
5465 TimeOuts.to_aconnect = toval;
5466 break;
5467
5468 case TO_QUEUEWARN:
5469 toval = convtime(val, 'h');
5470 TimeOuts.to_q_warning[TOC_NORMAL] = toval;
5471 TimeOuts.to_q_warning[TOC_URGENT] = toval;
5472 TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
5473 TimeOuts.to_q_warning[TOC_DSN] = toval;
5474 addopts = 2;
5475 break;
5476
5477 case TO_QUEUEWARN_NORMAL:
5478 toval = convtime(val, 'h');
5479 TimeOuts.to_q_warning[TOC_NORMAL] = toval;
5480 break;
5481
5482 case TO_QUEUEWARN_URGENT:
5483 toval = convtime(val, 'h');
5484 TimeOuts.to_q_warning[TOC_URGENT] = toval;
5485 break;
5486
5487 case TO_QUEUEWARN_NON_URGENT:
5488 toval = convtime(val, 'h');
5489 TimeOuts.to_q_warning[TOC_NONURGENT] = toval;
5490 break;
5491
5492 case TO_QUEUEWARN_DSN:
5493 toval = convtime(val, 'h');
5494 TimeOuts.to_q_warning[TOC_DSN] = toval;
5495 break;
5496
5497 case TO_QUEUERETURN:
5498 toval = convtime(val, 'd');
5499 TimeOuts.to_q_return[TOC_NORMAL] = toval;
5500 TimeOuts.to_q_return[TOC_URGENT] = toval;
5501 TimeOuts.to_q_return[TOC_NONURGENT] = toval;
5502 TimeOuts.to_q_return[TOC_DSN] = toval;
5503 addopts = 2;
5504 break;
5505
5506 case TO_QUEUERETURN_NORMAL:
5507 toval = convtime(val, 'd');
5508 TimeOuts.to_q_return[TOC_NORMAL] = toval;
5509 break;
5510
5511 case TO_QUEUERETURN_URGENT:
5512 toval = convtime(val, 'd');
5513 TimeOuts.to_q_return[TOC_URGENT] = toval;
5514 break;
5515
5516 case TO_QUEUERETURN_NON_URGENT:
5517 toval = convtime(val, 'd');
5518 TimeOuts.to_q_return[TOC_NONURGENT] = toval;
5519 break;
5520
5521 case TO_QUEUERETURN_DSN:
5522 toval = convtime(val, 'd');
5523 TimeOuts.to_q_return[TOC_DSN] = toval;
5524 break;
5525
5526 case TO_HOSTSTATUS:
5527 MciInfoTimeout = toval;
5528 break;
5529
5530 case TO_RESOLVER_RETRANS:
5531 toval = convtime(val, 's');
5532 TimeOuts.res_retrans[RES_TO_DEFAULT] = toval;
5533 TimeOuts.res_retrans[RES_TO_FIRST] = toval;
5534 TimeOuts.res_retrans[RES_TO_NORMAL] = toval;
5535 addopts = 2;
5536 break;
5537
5538 case TO_RESOLVER_RETRY:
5539 i = atoi(val);
5540 TimeOuts.res_retry[RES_TO_DEFAULT] = i;
5541 TimeOuts.res_retry[RES_TO_FIRST] = i;
5542 TimeOuts.res_retry[RES_TO_NORMAL] = i;
5543 addopts = 2;
5544 break;
5545
5546 case TO_RESOLVER_RETRANS_NORMAL:
5547 TimeOuts.res_retrans[RES_TO_NORMAL] = convtime(val, 's');
5548 break;
5549
5550 case TO_RESOLVER_RETRY_NORMAL:
5551 TimeOuts.res_retry[RES_TO_NORMAL] = atoi(val);
5552 break;
5553
5554 case TO_RESOLVER_RETRANS_FIRST:
5555 TimeOuts.res_retrans[RES_TO_FIRST] = convtime(val, 's');
5556 break;
5557
5558 case TO_RESOLVER_RETRY_FIRST:
5559 TimeOuts.res_retry[RES_TO_FIRST] = atoi(val);
5560 break;
5561
5562 case TO_CONTROL:
5563 TimeOuts.to_control = toval;
5564 break;
5565
5566 case TO_LHLO:
5567 TimeOuts.to_lhlo = toval;
5568 break;
5569
5570 #if SASL
5571 case TO_AUTH:
5572 TimeOuts.to_auth = toval;
5573 break;
5574 #endif
5575
5576 #if STARTTLS
5577 case TO_STARTTLS:
5578 TimeOuts.to_starttls = toval;
5579 break;
5580 #endif
5581
5582 default:
5583 syserr("settimeout: invalid timeout %s", name);
5584 break;
5585 }
5586
5587 if (sticky)
5588 {
5589 for (i = 0; i <= addopts; i++)
5590 setbitn(to->to_code + i, StickyTimeoutOpt);
5591 }
5592 }
5593 /*
5594 ** INITTIMEOUTS -- parse and set timeout values
5595 **
5596 ** Parameters:
5597 ** val -- a pointer to the values. If NULL, do initial
5598 ** settings.
5599 ** sticky -- if set, don't let other setoptions override
5600 ** this suboption value.
5601 **
5602 ** Returns:
5603 ** none.
5604 **
5605 ** Side Effects:
5606 ** Initializes the TimeOuts structure
5607 */
5608
5609 void
inittimeouts(val,sticky)5610 inittimeouts(val, sticky)
5611 register char *val;
5612 bool sticky;
5613 {
5614 register char *p;
5615
5616 if (tTd(37, 2))
5617 sm_dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val);
5618 if (val == NULL)
5619 {
5620 TimeOuts.to_connect = (time_t) 0 SECONDS;
5621 TimeOuts.to_aconnect = (time_t) 0 SECONDS;
5622 TimeOuts.to_iconnect = (time_t) 0 SECONDS;
5623 TimeOuts.to_initial = (time_t) 5 MINUTES;
5624 TimeOuts.to_helo = (time_t) 5 MINUTES;
5625 TimeOuts.to_mail = (time_t) 10 MINUTES;
5626 TimeOuts.to_rcpt = (time_t) 1 HOUR;
5627 TimeOuts.to_datainit = (time_t) 5 MINUTES;
5628 TimeOuts.to_datablock = (time_t) 1 HOUR;
5629 TimeOuts.to_datafinal = (time_t) 1 HOUR;
5630 TimeOuts.to_rset = (time_t) 5 MINUTES;
5631 TimeOuts.to_quit = (time_t) 2 MINUTES;
5632 TimeOuts.to_nextcommand = (time_t) 1 HOUR;
5633 TimeOuts.to_miscshort = (time_t) 2 MINUTES;
5634 #if IDENTPROTO
5635 TimeOuts.to_ident = (time_t) 5 SECONDS;
5636 #else
5637 TimeOuts.to_ident = (time_t) 0 SECONDS;
5638 #endif
5639 TimeOuts.to_fileopen = (time_t) 60 SECONDS;
5640 TimeOuts.to_control = (time_t) 2 MINUTES;
5641 TimeOuts.to_lhlo = (time_t) 2 MINUTES;
5642 #if SASL
5643 TimeOuts.to_auth = (time_t) 10 MINUTES;
5644 #endif
5645 #if STARTTLS
5646 TimeOuts.to_starttls = (time_t) 1 HOUR;
5647 #endif
5648 if (tTd(37, 5))
5649 {
5650 sm_dprintf("Timeouts:\n");
5651 sm_dprintf(" connect = %ld\n",
5652 (long) TimeOuts.to_connect);
5653 sm_dprintf(" aconnect = %ld\n",
5654 (long) TimeOuts.to_aconnect);
5655 sm_dprintf(" initial = %ld\n",
5656 (long) TimeOuts.to_initial);
5657 sm_dprintf(" helo = %ld\n", (long) TimeOuts.to_helo);
5658 sm_dprintf(" mail = %ld\n", (long) TimeOuts.to_mail);
5659 sm_dprintf(" rcpt = %ld\n", (long) TimeOuts.to_rcpt);
5660 sm_dprintf(" datainit = %ld\n",
5661 (long) TimeOuts.to_datainit);
5662 sm_dprintf(" datablock = %ld\n",
5663 (long) TimeOuts.to_datablock);
5664 sm_dprintf(" datafinal = %ld\n",
5665 (long) TimeOuts.to_datafinal);
5666 sm_dprintf(" rset = %ld\n", (long) TimeOuts.to_rset);
5667 sm_dprintf(" quit = %ld\n", (long) TimeOuts.to_quit);
5668 sm_dprintf(" nextcommand = %ld\n",
5669 (long) TimeOuts.to_nextcommand);
5670 sm_dprintf(" miscshort = %ld\n",
5671 (long) TimeOuts.to_miscshort);
5672 sm_dprintf(" ident = %ld\n", (long) TimeOuts.to_ident);
5673 sm_dprintf(" fileopen = %ld\n",
5674 (long) TimeOuts.to_fileopen);
5675 sm_dprintf(" lhlo = %ld\n",
5676 (long) TimeOuts.to_lhlo);
5677 sm_dprintf(" control = %ld\n",
5678 (long) TimeOuts.to_control);
5679 }
5680 return;
5681 }
5682
5683 for (;; val = p)
5684 {
5685 while (SM_ISSPACE(*val))
5686 val++;
5687 if (*val == '\0')
5688 break;
5689 for (p = val; *p != '\0' && *p != ','; p++)
5690 continue;
5691 if (*p != '\0')
5692 *p++ = '\0';
5693
5694 if (isascii(*val) && isdigit(*val))
5695 {
5696 /* old syntax -- set everything */
5697 TimeOuts.to_mail = convtime(val, 'm');
5698 TimeOuts.to_rcpt = TimeOuts.to_mail;
5699 TimeOuts.to_datainit = TimeOuts.to_mail;
5700 TimeOuts.to_datablock = TimeOuts.to_mail;
5701 TimeOuts.to_datafinal = TimeOuts.to_mail;
5702 TimeOuts.to_nextcommand = TimeOuts.to_mail;
5703 if (sticky)
5704 {
5705 setbitn(TO_MAIL, StickyTimeoutOpt);
5706 setbitn(TO_RCPT, StickyTimeoutOpt);
5707 setbitn(TO_DATAINIT, StickyTimeoutOpt);
5708 setbitn(TO_DATABLOCK, StickyTimeoutOpt);
5709 setbitn(TO_DATAFINAL, StickyTimeoutOpt);
5710 setbitn(TO_COMMAND, StickyTimeoutOpt);
5711 }
5712 continue;
5713 }
5714 else
5715 {
5716 register char *q = strchr(val, ':');
5717
5718 if (q == NULL && (q = strchr(val, '=')) == NULL)
5719 {
5720 /* syntax error */
5721 continue;
5722 }
5723 *q++ = '\0';
5724 settimeout(val, q, sticky);
5725 }
5726 }
5727 }
5728
5729 /*
5730 ** SHOWCFOPTS -- show cf options
5731 **
5732 ** Parameters:
5733 ** none
5734 **
5735 ** Returns:
5736 ** none.
5737 */
5738
5739 void
showcfopts()5740 showcfopts()
5741 {
5742 struct optioninfo *o;
5743
5744 for (o = OptionTab; o->o_name != NULL; o++)
5745 {
5746 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
5747 "%s\n", o->o_name);
5748 }
5749 }
5750