📄 readcf.c
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)readcf.c 8.23 (Berkeley) 3/18/94";#endif /* not lint */# include "sendmail.h"# include <pwd.h># include <grp.h>#if NAMED_BIND# include <arpa/nameser.h># include <resolv.h>#endif/*** READCF -- read control file.**** This routine reads the control file and builds the internal** form.**** The file is formatted as a sequence of lines, each taken** atomically. The first character of each line describes how** the line is to be interpreted. The lines are:** Dxval Define macro x to have value val.** Cxword Put word into class x.** Fxfile [fmt] Read file for lines to put into** class x. Use scanf string 'fmt'** or "%s" if not present. Fmt should** only produce one string-valued result.** Hname: value Define header with field-name 'name'** and value as specified; this will be** macro expanded immediately before** use.** Sn Use rewriting set n.** Rlhs rhs Rewrite addresses that match lhs to** be rhs.** Mn arg=val... Define mailer. n is the internal name.** Args specify mailer parameters.** Oxvalue Set option x to value.** Pname=value Set precedence name to value.** Vversioncode[/vendorcode]** Version level/vendor name of** configuration syntax.** Kmapname mapclass arguments....** Define keyed lookup of a given class.** Arguments are class dependent.**** Parameters:** cfname -- control file name.** safe -- TRUE if this is the system config file;** FALSE otherwise.** e -- the main envelope.**** Returns:** none.**** Side Effects:** Builds several internal tables.*/readcf(cfname, safe, e) char *cfname; bool safe; register ENVELOPE *e;{ FILE *cf; int ruleset = 0; char *q; struct rewrite *rwp = NULL; char *bp; auto char *ep; int nfuzzy; char *file; bool optional; char buf[MAXLINE]; register char *p; extern char **copyplist(); struct stat statb; char exbuf[MAXLINE]; char pvpbuf[MAXLINE + MAXATOM]; extern char *munchstring(); extern void makemapentry(); FileName = cfname; LineNumber = 0; cf = fopen(cfname, "r"); if (cf == NULL) { syserr("cannot open"); exit(EX_OSFILE); } if (fstat(fileno(cf), &statb) < 0) { syserr("cannot fstat"); exit(EX_OSFILE); } if (!S_ISREG(statb.st_mode)) { syserr("not a plain file"); exit(EX_OSFILE); } if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) { if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) fprintf(stderr, "%s: WARNING: dangerous write permissions\n", FileName);#ifdef LOG if (LogLevel > 0) syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", FileName);#endif }#ifdef XLA xla_zero();#endif while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) { if (bp[0] == '#') { if (bp != buf) free(bp); continue; } /* map $ into \201 for macro expansion */ for (p = bp; *p != '\0'; p++) { if (*p == '#' && p > bp && ConfigLevel >= 3) { /* this is an on-line comment */ register char *e; switch (*--p & 0377) { case MACROEXPAND: /* it's from $# -- let it go through */ p++; break; case '\\': /* it's backslash escaped */ (void) strcpy(p, p + 1); break; default: /* delete preceeding white space */ while (isascii(*p) && isspace(*p) && p > bp) p--; if ((e = strchr(++p, '\n')) != NULL) (void) strcpy(p, e); else p[0] = p[1] = '\0'; break; } continue; } if (*p != '$') continue; if (p[1] == '$') { /* actual dollar sign.... */ (void) strcpy(p, p + 1); continue; } /* convert to macro expansion character */ *p = MACROEXPAND; } /* interpret this line */ errno = 0; switch (bp[0]) { case '\0': case '#': /* comment */ break; case 'R': /* rewriting rule */ for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) continue; if (*p == '\0') { syserr("invalid rewrite line \"%s\" (tab expected)", bp); break; } /* allocate space for the rule header */ if (rwp == NULL) { RewriteRules[ruleset] = rwp = (struct rewrite *) xalloc(sizeof *rwp); } else { rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); rwp = rwp->r_next; } rwp->r_next = NULL; /* expand and save the LHS */ *p = '\0'; expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e); rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, sizeof pvpbuf, NULL); nfuzzy = 0; if (rwp->r_lhs != NULL) { register char **ap; rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); /* count the number of fuzzy matches in LHS */ for (ap = rwp->r_lhs; *ap != NULL; ap++) { char *botch; botch = NULL; switch (**ap & 0377) { case MATCHZANY: case MATCHANY: case MATCHONE: case MATCHCLASS: case MATCHNCLASS: nfuzzy++; break; case MATCHREPL: botch = "$0-$9"; break; case CANONNET: botch = "$#"; break; case CANONUSER: botch = "$:"; break; case CALLSUBR: botch = "$>"; break; case CONDIF: botch = "$?"; break; case CONDELSE: botch = "$|"; break; case CONDFI: botch = "$."; break; case HOSTBEGIN: botch = "$["; break; case HOSTEND: botch = "$]"; break; case LOOKUPBEGIN: botch = "$("; break; case LOOKUPEND: botch = "$)"; break; } if (botch != NULL) syserr("Inappropriate use of %s on LHS", botch); } } else syserr("R line: null LHS"); /* expand and save the RHS */ while (*++p == '\t') continue; q = p; while (*p != '\0' && *p != '\t') p++; *p = '\0'; expand(q, exbuf, &exbuf[sizeof exbuf], e); rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, sizeof pvpbuf, NULL); if (rwp->r_rhs != NULL) { register char **ap; rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); /* check no out-of-bounds replacements */ nfuzzy += '0'; for (ap = rwp->r_rhs; *ap != NULL; ap++) { char *botch; botch = NULL; switch (**ap & 0377) { case MATCHREPL: if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) { syserr("replacement $%c out of bounds", (*ap)[1]); } break; case MATCHZANY: botch = "$*"; break; case MATCHANY: botch = "$+"; break; case MATCHONE: botch = "$-"; break; case MATCHCLASS: botch = "$="; break; case MATCHNCLASS: botch = "$~"; break; } if (botch != NULL) syserr("Inappropriate use of %s on RHS", botch); } } else syserr("R line: null RHS"); break; case 'S': /* select rewriting set */ for (p = &bp[1]; isascii(*p) && isspace(*p); p++) continue; if (!isascii(*p) || !isdigit(*p)) { syserr("invalid argument to S line: \"%.20s\"", &bp[1]); break; } ruleset = atoi(p); if (ruleset >= MAXRWSETS || ruleset < 0) { syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); ruleset = 0; } rwp = NULL; break; case 'D': /* macro definition */ p = munchstring(&bp[2], NULL); define(bp[1], newstr(p), e); break; case 'H': /* required header line */ (void) chompheader(&bp[1], TRUE, e); break; case 'C': /* word class */ /* scan the list of words and set class for all */ expand(&bp[2], exbuf, &exbuf[sizeof exbuf], e); for (p = exbuf; *p != '\0'; ) { register char *wd; char delim; while (*p != '\0' && isascii(*p) && isspace(*p)) p++; wd = p; while (*p != '\0' && !(isascii(*p) && isspace(*p))) p++; delim = *p; *p = '\0'; if (wd[0] != '\0') setclass(bp[1], wd); *p = delim; } break; case 'F': /* word class from file */ for (p = &bp[2]; isascii(*p) && isspace(*p); ) p++; if (p[0] == '-' && p[1] == 'o') { optional = TRUE; while (*p != '\0' && !(isascii(*p) && isspace(*p))) p++; while (isascii(*p) && isspace(*p)) *p++; } else optional = FALSE; file = p; while (*p != '\0' && !(isascii(*p) && isspace(*p))) p++; if (*p == '\0') p = "%s"; else { *p = '\0'; while (isascii(*++p) && isspace(*p)) continue; } fileclass(bp[1], file, p, safe, optional); break;#ifdef XLA case 'L': /* extended load average description */ xla_init(&bp[1]); break;#endif case 'M': /* define mailer */ makemailer(&bp[1]); break; case 'O': /* set option */ setoption(bp[1], &bp[2], safe, FALSE, e); break; case 'P': /* set precedence */ if (NumPriorities >= MAXPRIORITIES) { toomany('P', MAXPRIORITIES); break; } for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) continue; if (*p == '\0') goto badline; *p = '\0'; Priorities[NumPriorities].pri_name = newstr(&bp[1]); Priorities[NumPriorities].pri_val = atoi(++p); NumPriorities++; break; case 'T': /* trusted user(s) */ /* this option is obsolete, but will be ignored */ break; case 'V': /* configuration syntax version */ for (p = &bp[1]; isascii(*p) && isspace(*p); p++) continue; if (!isascii(*p) || !isdigit(*p)) { syserr("invalid argument to V line: \"%.20s\"", &bp[1]); break; } ConfigLevel = strtol(p, &ep, 10); if (ConfigLevel >= 5) { /* level 5 configs have short name in $w */ p = macvalue('w', e); if (p != NULL && (p = strchr(p, '.')) != NULL) *p = '\0'; } if (*ep++ == '/') { /* extract vendor code */ for (p = ep; isascii(*p) && isalpha(*p); ) p++; *p = '\0'; if (!setvendor(ep)) syserr("invalid V line vendor code: \"%s\"", ep); } break; case 'K': makemapentry(&bp[1]); break; default: badline: syserr("unknown control line \"%s\"", bp); } if (bp != buf) free(bp); } if (ferror(cf)) { syserr("I/O read error", cfname); exit(EX_OSFILE); } fclose(cf); FileName = NULL; if (stab("host", ST_MAP, ST_FIND) == NULL) { /* user didn't initialize: set up host map */ strcpy(buf, "host host");#if NAMED_BIND if (ConfigLevel >= 2) strcat(buf, " -a.");#endif makemapentry(buf); }}/*** TOOMANY -- signal too many of some option**** Parameters:** id -- the id of the error line** maxcnt -- the maximum possible values**** Returns:** none.**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -