122709Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822709Sdist 922709Sdist #ifndef lint 10*52647Seric static char sccsid[] = "@(#)readcf.c 5.34 (Berkeley) 02/24/92"; 1133731Sbostic #endif /* not lint */ 1222709Sdist 133313Seric # include "sendmail.h" 14*52647Seric # include <sys/stat.h> 153308Seric 163308Seric /* 173308Seric ** READCF -- read control file. 183308Seric ** 193308Seric ** This routine reads the control file and builds the internal 203308Seric ** form. 213308Seric ** 224432Seric ** The file is formatted as a sequence of lines, each taken 234432Seric ** atomically. The first character of each line describes how 244432Seric ** the line is to be interpreted. The lines are: 254432Seric ** Dxval Define macro x to have value val. 264432Seric ** Cxword Put word into class x. 274432Seric ** Fxfile [fmt] Read file for lines to put into 284432Seric ** class x. Use scanf string 'fmt' 294432Seric ** or "%s" if not present. Fmt should 304432Seric ** only produce one string-valued result. 314432Seric ** Hname: value Define header with field-name 'name' 324432Seric ** and value as specified; this will be 334432Seric ** macro expanded immediately before 344432Seric ** use. 354432Seric ** Sn Use rewriting set n. 364432Seric ** Rlhs rhs Rewrite addresses that match lhs to 374432Seric ** be rhs. 3824944Seric ** Mn arg=val... Define mailer. n is the internal name. 3924944Seric ** Args specify mailer parameters. 408252Seric ** Oxvalue Set option x to value. 418252Seric ** Pname=value Set precedence name to value. 4252645Seric ** Vversioncode Version level of configuration syntax. 434432Seric ** 443308Seric ** Parameters: 453308Seric ** cfname -- control file name. 463308Seric ** 473308Seric ** Returns: 483308Seric ** none. 493308Seric ** 503308Seric ** Side Effects: 513308Seric ** Builds several internal tables. 523308Seric */ 533308Seric 5421066Seric readcf(cfname) 553308Seric char *cfname; 563308Seric { 573308Seric FILE *cf; 588547Seric int ruleset = 0; 598547Seric char *q; 608547Seric char **pv; 619350Seric struct rewrite *rwp = NULL; 623308Seric char buf[MAXLINE]; 633308Seric register char *p; 643308Seric extern char **prescan(); 653308Seric extern char **copyplist(); 66*52647Seric struct stat statb; 675909Seric char exbuf[MAXLINE]; 6816915Seric char pvpbuf[PSBUFSIZE]; 699350Seric extern char *fgetfolded(); 7010709Seric extern char *munchstring(); 713308Seric 72*52647Seric FileName = cfname; 73*52647Seric LineNumber = 0; 74*52647Seric 753308Seric cf = fopen(cfname, "r"); 763308Seric if (cf == NULL) 773308Seric { 78*52647Seric syserr("cannot open"); 793308Seric exit(EX_OSFILE); 803308Seric } 813308Seric 82*52647Seric if (fstat(fileno(cf), &statb) < 0) 83*52647Seric { 84*52647Seric syserr("cannot fstat"); 85*52647Seric exit(EX_OSFILE); 86*52647Seric } 87*52647Seric 88*52647Seric if (!S_ISREG(statb.st_mode)) 89*52647Seric { 90*52647Seric syserr("not a plain file"); 91*52647Seric exit(EX_OSFILE); 92*52647Seric } 93*52647Seric 94*52647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 95*52647Seric { 96*52647Seric syserr("WARNING: dangerous write permissions"); 97*52647Seric } 98*52647Seric 997854Seric while (fgetfolded(buf, sizeof buf, cf) != NULL) 1003308Seric { 10152637Seric if (buf[0] == '#') 10252637Seric continue; 10352637Seric 10416157Seric /* map $ into \001 (ASCII SOH) for macro expansion */ 10516157Seric for (p = buf; *p != '\0'; p++) 10616157Seric { 107*52647Seric if (*p == '#' && p > buf && ConfigLevel >= 3) 108*52647Seric { 109*52647Seric /* this is an on-line comment */ 110*52647Seric register char *e; 111*52647Seric 112*52647Seric switch (*--p) 113*52647Seric { 114*52647Seric case '\001': 115*52647Seric /* it's from $# -- let it go through */ 116*52647Seric p++; 117*52647Seric break; 118*52647Seric 119*52647Seric case '\\': 120*52647Seric /* it's backslash escaped */ 121*52647Seric (void) strcpy(p, p + 1); 122*52647Seric break; 123*52647Seric 124*52647Seric default: 125*52647Seric /* delete preceeding white space */ 126*52647Seric while (isspace(*p) && p > buf) 127*52647Seric p--; 128*52647Seric if ((e = index(++p, '\n')) != NULL) 129*52647Seric (void) strcpy(p, e); 130*52647Seric else 131*52647Seric p[0] = p[1] = '\0'; 132*52647Seric break; 133*52647Seric } 134*52647Seric continue; 135*52647Seric } 136*52647Seric 13716157Seric if (*p != '$') 13816157Seric continue; 13916157Seric 14016157Seric if (p[1] == '$') 14116157Seric { 14216157Seric /* actual dollar sign.... */ 14323111Seric (void) strcpy(p, p + 1); 14416157Seric continue; 14516157Seric } 14616157Seric 14716157Seric /* convert to macro expansion character */ 14816157Seric *p = '\001'; 14916157Seric } 15016157Seric 15116157Seric /* interpret this line */ 1523308Seric switch (buf[0]) 1533308Seric { 1543308Seric case '\0': 1553308Seric case '#': /* comment */ 1563308Seric break; 1573308Seric 1583308Seric case 'R': /* rewriting rule */ 1593308Seric for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 1603308Seric continue; 1613308Seric 1623308Seric if (*p == '\0') 1635909Seric { 1649381Seric syserr("invalid rewrite line \"%s\"", buf); 1655909Seric break; 1665909Seric } 1675909Seric 1685909Seric /* allocate space for the rule header */ 1695909Seric if (rwp == NULL) 1705909Seric { 1715909Seric RewriteRules[ruleset] = rwp = 1725909Seric (struct rewrite *) xalloc(sizeof *rwp); 1735909Seric } 1743308Seric else 1753308Seric { 1765909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 1775909Seric rwp = rwp->r_next; 1785909Seric } 1795909Seric rwp->r_next = NULL; 1803308Seric 1815909Seric /* expand and save the LHS */ 1825909Seric *p = '\0'; 1836991Seric expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv); 18416915Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf); 1855909Seric if (rwp->r_lhs != NULL) 1865909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 1875909Seric 1885909Seric /* expand and save the RHS */ 1895909Seric while (*++p == '\t') 1905909Seric continue; 1917231Seric q = p; 1927231Seric while (*p != '\0' && *p != '\t') 1937231Seric p++; 1947231Seric *p = '\0'; 1957231Seric expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv); 19616915Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf); 1975909Seric if (rwp->r_rhs != NULL) 1985909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 1993308Seric break; 2003308Seric 2014072Seric case 'S': /* select rewriting set */ 2024072Seric ruleset = atoi(&buf[1]); 2038056Seric if (ruleset >= MAXRWSETS || ruleset < 0) 2048056Seric { 2059381Seric syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 2068056Seric ruleset = 0; 2078056Seric } 2084072Seric rwp = NULL; 2094072Seric break; 2104072Seric 2113308Seric case 'D': /* macro definition */ 21210709Seric define(buf[1], newstr(munchstring(&buf[2])), CurEnv); 2133308Seric break; 2143308Seric 2153387Seric case 'H': /* required header line */ 2164088Seric (void) chompheader(&buf[1], TRUE); 2173387Seric break; 2183387Seric 2194061Seric case 'C': /* word class */ 2204432Seric case 'F': /* word class from file */ 2214432Seric /* read list of words from argument or file */ 2224432Seric if (buf[0] == 'F') 2234432Seric { 2244432Seric /* read from file */ 2254432Seric for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 2264432Seric continue; 2274432Seric if (*p == '\0') 2284432Seric p = "%s"; 2294432Seric else 2304432Seric { 2314432Seric *p = '\0'; 2324432Seric while (isspace(*++p)) 2334432Seric continue; 2344432Seric } 23510687Seric fileclass(buf[1], &buf[2], p); 2364432Seric break; 2374432Seric } 2384061Seric 2394432Seric /* scan the list of words and set class for all */ 2404061Seric for (p = &buf[2]; *p != '\0'; ) 2414061Seric { 2424061Seric register char *wd; 2434061Seric char delim; 2444061Seric 2454061Seric while (*p != '\0' && isspace(*p)) 2464061Seric p++; 2474061Seric wd = p; 2484061Seric while (*p != '\0' && !isspace(*p)) 2494061Seric p++; 2504061Seric delim = *p; 2514061Seric *p = '\0'; 2524061Seric if (wd[0] != '\0') 25310687Seric setclass(buf[1], wd); 2544061Seric *p = delim; 2554061Seric } 2564061Seric break; 2574061Seric 2584096Seric case 'M': /* define mailer */ 25921066Seric makemailer(&buf[1]); 2604096Seric break; 2614096Seric 2628252Seric case 'O': /* set option */ 26321755Seric setoption(buf[1], &buf[2], TRUE, FALSE); 2648252Seric break; 2658252Seric 2668252Seric case 'P': /* set precedence */ 2678252Seric if (NumPriorities >= MAXPRIORITIES) 2688252Seric { 2698547Seric toomany('P', MAXPRIORITIES); 2708252Seric break; 2718252Seric } 2729381Seric for (p = &buf[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 2738252Seric continue; 2748252Seric if (*p == '\0') 2758252Seric goto badline; 2768252Seric *p = '\0'; 2778252Seric Priorities[NumPriorities].pri_name = newstr(&buf[1]); 2788252Seric Priorities[NumPriorities].pri_val = atoi(++p); 2798252Seric NumPriorities++; 2808252Seric break; 2818252Seric 2828547Seric case 'T': /* trusted user(s) */ 2838547Seric p = &buf[1]; 2848547Seric while (*p != '\0') 2858547Seric { 2868547Seric while (isspace(*p)) 2878547Seric p++; 2888547Seric q = p; 2898547Seric while (*p != '\0' && !isspace(*p)) 2908547Seric p++; 2918547Seric if (*p != '\0') 2928547Seric *p++ = '\0'; 2938547Seric if (*q == '\0') 2948547Seric continue; 2958547Seric for (pv = TrustedUsers; *pv != NULL; pv++) 2968547Seric continue; 2978547Seric if (pv >= &TrustedUsers[MAXTRUST]) 2988547Seric { 2998547Seric toomany('T', MAXTRUST); 3008547Seric break; 3018547Seric } 3028547Seric *pv = newstr(q); 3038547Seric } 3048547Seric break; 3058547Seric 30652645Seric case 'V': /* configuration syntax version */ 30752645Seric ConfigLevel = atoi(&buf[1]); 30852645Seric break; 30952645Seric 3103308Seric default: 3114061Seric badline: 3129381Seric syserr("unknown control line \"%s\"", buf); 3133308Seric } 3143308Seric } 31552637Seric if (ferror(cf)) 31652637Seric { 317*52647Seric syserr("I/O read error", cfname); 31852637Seric exit(EX_OSFILE); 31952637Seric } 32052637Seric fclose(cf); 3219381Seric FileName = NULL; 3224096Seric } 3234096Seric /* 3248547Seric ** TOOMANY -- signal too many of some option 3258547Seric ** 3268547Seric ** Parameters: 3278547Seric ** id -- the id of the error line 3288547Seric ** maxcnt -- the maximum possible values 3298547Seric ** 3308547Seric ** Returns: 3318547Seric ** none. 3328547Seric ** 3338547Seric ** Side Effects: 3348547Seric ** gives a syserr. 3358547Seric */ 3368547Seric 3378547Seric toomany(id, maxcnt) 3388547Seric char id; 3398547Seric int maxcnt; 3408547Seric { 3419381Seric syserr("too many %c lines, %d max", id, maxcnt); 3428547Seric } 3438547Seric /* 3444432Seric ** FILECLASS -- read members of a class from a file 3454432Seric ** 3464432Seric ** Parameters: 3474432Seric ** class -- class to define. 3484432Seric ** filename -- name of file to read. 3494432Seric ** fmt -- scanf string to use for match. 3504432Seric ** 3514432Seric ** Returns: 3524432Seric ** none 3534432Seric ** 3544432Seric ** Side Effects: 3554432Seric ** 3564432Seric ** puts all lines in filename that match a scanf into 3574432Seric ** the named class. 3584432Seric */ 3594432Seric 3604432Seric fileclass(class, filename, fmt) 3614432Seric int class; 3624432Seric char *filename; 3634432Seric char *fmt; 3644432Seric { 36525808Seric FILE *f; 3664432Seric char buf[MAXLINE]; 3674432Seric 36852062Seric if (filename[0] == '|') 36952062Seric f = popen(filename + 1, "r"); 37052062Seric else 37152062Seric f = fopen(filename, "r"); 3724432Seric if (f == NULL) 3734432Seric { 3744432Seric syserr("cannot open %s", filename); 3754432Seric return; 3764432Seric } 3774432Seric 3784432Seric while (fgets(buf, sizeof buf, f) != NULL) 3794432Seric { 3804432Seric register STAB *s; 38125808Seric register char *p; 38225808Seric # ifdef SCANF 3834432Seric char wordbuf[MAXNAME+1]; 3844432Seric 3854432Seric if (sscanf(buf, fmt, wordbuf) != 1) 3864432Seric continue; 38725808Seric p = wordbuf; 38825808Seric # else SCANF 38925808Seric p = buf; 39025808Seric # endif SCANF 39125808Seric 39225808Seric /* 39325808Seric ** Break up the match into words. 39425808Seric */ 39525808Seric 39625808Seric while (*p != '\0') 39725808Seric { 39825808Seric register char *q; 39925808Seric 40025808Seric /* strip leading spaces */ 40125808Seric while (isspace(*p)) 40225808Seric p++; 40325808Seric if (*p == '\0') 40425808Seric break; 40525808Seric 40625808Seric /* find the end of the word */ 40725808Seric q = p; 40825808Seric while (*p != '\0' && !isspace(*p)) 40925808Seric p++; 41025808Seric if (*p != '\0') 41125808Seric *p++ = '\0'; 41225808Seric 41325808Seric /* enter the word in the symbol table */ 41425808Seric s = stab(q, ST_CLASS, ST_ENTER); 41525808Seric setbitn(class, s->s_class); 41625808Seric } 4174432Seric } 4184432Seric 41952062Seric if (filename[0] == '|') 42052062Seric (void) pclose(f); 42152062Seric else 42252062Seric (void) fclose(f); 4234432Seric } 4244432Seric /* 4254096Seric ** MAKEMAILER -- define a new mailer. 4264096Seric ** 4274096Seric ** Parameters: 42810327Seric ** line -- description of mailer. This is in labeled 42910327Seric ** fields. The fields are: 43010327Seric ** P -- the path to the mailer 43110327Seric ** F -- the flags associated with the mailer 43210327Seric ** A -- the argv for this mailer 43310327Seric ** S -- the sender rewriting set 43410327Seric ** R -- the recipient rewriting set 43510327Seric ** E -- the eol string 43610327Seric ** The first word is the canonical name of the mailer. 4374096Seric ** 4384096Seric ** Returns: 4394096Seric ** none. 4404096Seric ** 4414096Seric ** Side Effects: 4424096Seric ** enters the mailer into the mailer table. 4434096Seric */ 4443308Seric 44521066Seric makemailer(line) 4464096Seric char *line; 4474096Seric { 4484096Seric register char *p; 4498067Seric register struct mailer *m; 4508067Seric register STAB *s; 4518067Seric int i; 45210327Seric char fcode; 4534096Seric extern int NextMailer; 45410327Seric extern char **makeargv(); 45510327Seric extern char *munchstring(); 45610327Seric extern char *DelimChar; 45710701Seric extern long atol(); 4584096Seric 45910327Seric /* allocate a mailer and set up defaults */ 46010327Seric m = (struct mailer *) xalloc(sizeof *m); 46110327Seric bzero((char *) m, sizeof *m); 46210327Seric m->m_mno = NextMailer; 46310327Seric m->m_eol = "\n"; 46410327Seric 46510327Seric /* collect the mailer name */ 46610327Seric for (p = line; *p != '\0' && *p != ',' && !isspace(*p); p++) 46710327Seric continue; 46810327Seric if (*p != '\0') 46910327Seric *p++ = '\0'; 47010327Seric m->m_name = newstr(line); 47110327Seric 47210327Seric /* now scan through and assign info from the fields */ 47310327Seric while (*p != '\0') 47410327Seric { 47510327Seric while (*p != '\0' && (*p == ',' || isspace(*p))) 47610327Seric p++; 47710327Seric 47810327Seric /* p now points to field code */ 47910327Seric fcode = *p; 48010327Seric while (*p != '\0' && *p != '=' && *p != ',') 48110327Seric p++; 48210327Seric if (*p++ != '=') 48310327Seric { 48452637Seric syserr("mailer %s: `=' expected", m->m_name); 48510327Seric return; 48610327Seric } 48710327Seric while (isspace(*p)) 48810327Seric p++; 48910327Seric 49010327Seric /* p now points to the field body */ 49110327Seric p = munchstring(p); 49210327Seric 49310327Seric /* install the field into the mailer struct */ 49410327Seric switch (fcode) 49510327Seric { 49610327Seric case 'P': /* pathname */ 49710327Seric m->m_mailer = newstr(p); 49810327Seric break; 49910327Seric 50010327Seric case 'F': /* flags */ 50110687Seric for (; *p != '\0'; p++) 50252637Seric if (!isspace(*p)) 50352637Seric setbitn(*p, m->m_flags); 50410327Seric break; 50510327Seric 50610327Seric case 'S': /* sender rewriting ruleset */ 50710327Seric case 'R': /* recipient rewriting ruleset */ 50810327Seric i = atoi(p); 50910327Seric if (i < 0 || i >= MAXRWSETS) 51010327Seric { 51110327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 51210327Seric return; 51310327Seric } 51410327Seric if (fcode == 'S') 51510327Seric m->m_s_rwset = i; 51610327Seric else 51710327Seric m->m_r_rwset = i; 51810327Seric break; 51910327Seric 52010327Seric case 'E': /* end of line string */ 52110327Seric m->m_eol = newstr(p); 52210327Seric break; 52310327Seric 52410327Seric case 'A': /* argument vector */ 52510327Seric m->m_argv = makeargv(p); 52610327Seric break; 52710701Seric 52810701Seric case 'M': /* maximum message size */ 52910701Seric m->m_maxsize = atol(p); 53010701Seric break; 53152106Seric 53252106Seric case 'L': /* maximum line length */ 53352106Seric m->m_linelimit = atoi(p); 53452106Seric break; 53510327Seric } 53610327Seric 53710327Seric p = DelimChar; 53810327Seric } 53910327Seric 54052106Seric /* do some heuristic cleanup for back compatibility */ 54152106Seric if (bitnset(M_LIMITS, m->m_flags)) 54252106Seric { 54352106Seric if (m->m_linelimit == 0) 54452106Seric m->m_linelimit = SMTPLINELIM; 54552106Seric if (!bitnset(M_8BITS, m->m_flags)) 54652106Seric setbitn(M_7BITS, m->m_flags); 54752106Seric } 54852106Seric 54910327Seric /* now store the mailer away */ 5504096Seric if (NextMailer >= MAXMAILERS) 5514096Seric { 5529381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 5534096Seric return; 5544096Seric } 55510327Seric Mailer[NextMailer++] = m; 55610327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 55710327Seric s->s_mailer = m; 55810327Seric } 55910327Seric /* 56010327Seric ** MUNCHSTRING -- translate a string into internal form. 56110327Seric ** 56210327Seric ** Parameters: 56310327Seric ** p -- the string to munch. 56410327Seric ** 56510327Seric ** Returns: 56610327Seric ** the munched string. 56710327Seric ** 56810327Seric ** Side Effects: 56910327Seric ** Sets "DelimChar" to point to the string that caused us 57010327Seric ** to stop. 57110327Seric */ 5724096Seric 57310327Seric char * 57410327Seric munchstring(p) 57510327Seric register char *p; 57610327Seric { 57710327Seric register char *q; 57810327Seric bool backslash = FALSE; 57910327Seric bool quotemode = FALSE; 58010327Seric static char buf[MAXLINE]; 58110327Seric extern char *DelimChar; 5824096Seric 58310327Seric for (q = buf; *p != '\0'; p++) 5844096Seric { 58510327Seric if (backslash) 58610327Seric { 58710327Seric /* everything is roughly literal */ 58810357Seric backslash = FALSE; 58910327Seric switch (*p) 59010327Seric { 59110327Seric case 'r': /* carriage return */ 59210327Seric *q++ = '\r'; 59310327Seric continue; 59410327Seric 59510327Seric case 'n': /* newline */ 59610327Seric *q++ = '\n'; 59710327Seric continue; 59810327Seric 59910327Seric case 'f': /* form feed */ 60010327Seric *q++ = '\f'; 60110327Seric continue; 60210327Seric 60310327Seric case 'b': /* backspace */ 60410327Seric *q++ = '\b'; 60510327Seric continue; 60610327Seric } 60710327Seric *q++ = *p; 60810327Seric } 60910327Seric else 61010327Seric { 61110327Seric if (*p == '\\') 61210327Seric backslash = TRUE; 61310327Seric else if (*p == '"') 61410327Seric quotemode = !quotemode; 61510327Seric else if (quotemode || *p != ',') 61610327Seric *q++ = *p; 61710327Seric else 61810327Seric break; 61910327Seric } 6204096Seric } 6214096Seric 62210327Seric DelimChar = p; 62310327Seric *q++ = '\0'; 62410327Seric return (buf); 62510327Seric } 62610327Seric /* 62710327Seric ** MAKEARGV -- break up a string into words 62810327Seric ** 62910327Seric ** Parameters: 63010327Seric ** p -- the string to break up. 63110327Seric ** 63210327Seric ** Returns: 63310327Seric ** a char **argv (dynamically allocated) 63410327Seric ** 63510327Seric ** Side Effects: 63610327Seric ** munges p. 63710327Seric */ 6384096Seric 63910327Seric char ** 64010327Seric makeargv(p) 64110327Seric register char *p; 64210327Seric { 64310327Seric char *q; 64410327Seric int i; 64510327Seric char **avp; 64610327Seric char *argv[MAXPV + 1]; 64710327Seric 64810327Seric /* take apart the words */ 64910327Seric i = 0; 65010327Seric while (*p != '\0' && i < MAXPV) 6514096Seric { 65210327Seric q = p; 65310327Seric while (*p != '\0' && !isspace(*p)) 65410327Seric p++; 65510327Seric while (isspace(*p)) 65610327Seric *p++ = '\0'; 65710327Seric argv[i++] = newstr(q); 6584096Seric } 65910327Seric argv[i++] = NULL; 6604096Seric 66110327Seric /* now make a copy of the argv */ 66210327Seric avp = (char **) xalloc(sizeof *avp * i); 66316893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 66410327Seric 66510327Seric return (avp); 6663308Seric } 6673308Seric /* 6683308Seric ** PRINTRULES -- print rewrite rules (for debugging) 6693308Seric ** 6703308Seric ** Parameters: 6713308Seric ** none. 6723308Seric ** 6733308Seric ** Returns: 6743308Seric ** none. 6753308Seric ** 6763308Seric ** Side Effects: 6773308Seric ** prints rewrite rules. 6783308Seric */ 6793308Seric 6803308Seric printrules() 6813308Seric { 6823308Seric register struct rewrite *rwp; 6834072Seric register int ruleset; 6843308Seric 6854072Seric for (ruleset = 0; ruleset < 10; ruleset++) 6863308Seric { 6874072Seric if (RewriteRules[ruleset] == NULL) 6884072Seric continue; 6898067Seric printf("\n----Rule Set %d:", ruleset); 6903308Seric 6914072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 6923308Seric { 6938067Seric printf("\nLHS:"); 6948067Seric printav(rwp->r_lhs); 6958067Seric printf("RHS:"); 6968067Seric printav(rwp->r_rhs); 6973308Seric } 6983308Seric } 6993308Seric } 7004319Seric 7014096Seric /* 7028256Seric ** SETOPTION -- set global processing option 7038256Seric ** 7048256Seric ** Parameters: 7058256Seric ** opt -- option name. 7068256Seric ** val -- option value (as a text string). 70721755Seric ** safe -- set if this came from a configuration file. 70821755Seric ** Some options (if set from the command line) will 70921755Seric ** reset the user id to avoid security problems. 7108269Seric ** sticky -- if set, don't let other setoptions override 7118269Seric ** this value. 7128256Seric ** 7138256Seric ** Returns: 7148256Seric ** none. 7158256Seric ** 7168256Seric ** Side Effects: 7178256Seric ** Sets options as implied by the arguments. 7188256Seric */ 7198256Seric 72010687Seric static BITMAP StickyOpt; /* set if option is stuck */ 7218269Seric 72221755Seric setoption(opt, val, safe, sticky) 7238256Seric char opt; 7248256Seric char *val; 72521755Seric bool safe; 7268269Seric bool sticky; 7278256Seric { 7288265Seric extern bool atobool(); 72912633Seric extern time_t convtime(); 73014879Seric extern int QueueLA; 73114879Seric extern int RefuseLA; 73217474Seric extern bool trusteduser(); 73317474Seric extern char *username(); 7348256Seric 7358256Seric if (tTd(37, 1)) 7369341Seric printf("setoption %c=%s", opt, val); 7378256Seric 7388256Seric /* 7398269Seric ** See if this option is preset for us. 7408256Seric */ 7418256Seric 74210687Seric if (bitnset(opt, StickyOpt)) 7438269Seric { 7449341Seric if (tTd(37, 1)) 7459341Seric printf(" (ignored)\n"); 7468269Seric return; 7478269Seric } 7488269Seric 74921755Seric /* 75021755Seric ** Check to see if this option can be specified by this user. 75121755Seric */ 75221755Seric 75336238Skarels if (!safe && getuid() == 0) 75421755Seric safe = TRUE; 75521755Seric if (!safe && index("deiLmorsv", opt) == NULL) 75621755Seric { 75739111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 75821755Seric { 75936582Sbostic if (tTd(37, 1)) 76036582Sbostic printf(" (unsafe)"); 76136582Sbostic if (getuid() != geteuid()) 76236582Sbostic { 76351210Seric if (tTd(37, 1)) 76451210Seric printf("(Resetting uid)"); 76536582Sbostic (void) setgid(getgid()); 76636582Sbostic (void) setuid(getuid()); 76736582Sbostic } 76821755Seric } 76921755Seric } 77051210Seric if (tTd(37, 1)) 77117985Seric printf("\n"); 7728269Seric 7738256Seric switch (opt) 7748256Seric { 77551312Seric case '=': /* config file generation level */ 77651312Seric ConfigLevel = atoi(val); 77751312Seric break; 77851312Seric 77952106Seric case '8': /* allow eight-bit input */ 78052106Seric EightBit = atobool(val); 78152106Seric break; 78252106Seric 7838256Seric case 'A': /* set default alias file */ 7849381Seric if (val[0] == '\0') 7858269Seric AliasFile = "aliases"; 7869381Seric else 7879381Seric AliasFile = newstr(val); 7888256Seric break; 7898256Seric 79017474Seric case 'a': /* look N minutes for "@:@" in alias file */ 79117474Seric if (val[0] == '\0') 79217474Seric SafeAlias = 5; 79317474Seric else 79417474Seric SafeAlias = atoi(val); 79517474Seric break; 79617474Seric 79716843Seric case 'B': /* substitution for blank character */ 79816843Seric SpaceSub = val[0]; 79916843Seric if (SpaceSub == '\0') 80016843Seric SpaceSub = ' '; 80116843Seric break; 80216843Seric 8039284Seric case 'c': /* don't connect to "expensive" mailers */ 8049381Seric NoConnect = atobool(val); 8059284Seric break; 8069284Seric 80751305Seric case 'C': /* checkpoint every N addresses */ 80851305Seric CheckpointInterval = atoi(val); 80924944Seric break; 81024944Seric 8119284Seric case 'd': /* delivery mode */ 8129284Seric switch (*val) 8138269Seric { 8149284Seric case '\0': 8159284Seric SendMode = SM_DELIVER; 8168269Seric break; 8178269Seric 81810755Seric case SM_QUEUE: /* queue only */ 81910755Seric #ifndef QUEUE 82010755Seric syserr("need QUEUE to set -odqueue"); 82110755Seric #endif QUEUE 82210755Seric /* fall through..... */ 82310755Seric 8249284Seric case SM_DELIVER: /* do everything */ 8259284Seric case SM_FORK: /* fork after verification */ 8269284Seric SendMode = *val; 8278269Seric break; 8288269Seric 8298269Seric default: 8309284Seric syserr("Unknown delivery mode %c", *val); 8318269Seric exit(EX_USAGE); 8328269Seric } 8338269Seric break; 8348269Seric 8359146Seric case 'D': /* rebuild alias database as needed */ 8369381Seric AutoRebuild = atobool(val); 8379146Seric break; 8389146Seric 8398269Seric case 'e': /* set error processing mode */ 8408269Seric switch (*val) 8418269Seric { 8429381Seric case EM_QUIET: /* be silent about it */ 8439381Seric case EM_MAIL: /* mail back */ 8449381Seric case EM_BERKNET: /* do berknet error processing */ 8459381Seric case EM_WRITE: /* write back (or mail) */ 8468269Seric HoldErrs = TRUE; 8479381Seric /* fall through... */ 8488269Seric 8499381Seric case EM_PRINT: /* print errors normally (default) */ 8509381Seric ErrorMode = *val; 8518269Seric break; 8528269Seric } 8538269Seric break; 8548269Seric 8559049Seric case 'F': /* file mode */ 85617975Seric FileMode = atooct(val) & 0777; 8579049Seric break; 8589049Seric 8598269Seric case 'f': /* save Unix-style From lines on front */ 8609381Seric SaveFrom = atobool(val); 8618269Seric break; 8628269Seric 8638256Seric case 'g': /* default gid */ 86417474Seric DefGid = atoi(val); 8658256Seric break; 8668256Seric 8678256Seric case 'H': /* help file */ 8689381Seric if (val[0] == '\0') 8698269Seric HelpFile = "sendmail.hf"; 8709381Seric else 8719381Seric HelpFile = newstr(val); 8728256Seric break; 8738256Seric 87451305Seric case 'h': /* maximum hop count */ 87551305Seric MaxHopCount = atoi(val); 87651305Seric break; 87751305Seric 87835651Seric case 'I': /* use internet domain name server */ 87935651Seric UseNameServer = atobool(val); 88035651Seric break; 88135651Seric 8828269Seric case 'i': /* ignore dot lines in message */ 8839381Seric IgnrDot = atobool(val); 8848269Seric break; 8858269Seric 8868256Seric case 'L': /* log level */ 8879381Seric LogLevel = atoi(val); 8888256Seric break; 8898256Seric 8908269Seric case 'M': /* define macro */ 8919381Seric define(val[0], newstr(&val[1]), CurEnv); 89216878Seric sticky = FALSE; 8938269Seric break; 8948269Seric 8958269Seric case 'm': /* send to me too */ 8969381Seric MeToo = atobool(val); 8978269Seric break; 8988269Seric 89925820Seric case 'n': /* validate RHS in newaliases */ 90025820Seric CheckAliases = atobool(val); 90125820Seric break; 90225820Seric 9038269Seric case 'o': /* assume old style headers */ 9049381Seric if (atobool(val)) 9059341Seric CurEnv->e_flags |= EF_OLDSTYLE; 9069341Seric else 9079341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 9088269Seric break; 9098269Seric 91024944Seric case 'P': /* postmaster copy address for returned mail */ 91124944Seric PostMasterCopy = newstr(val); 91224944Seric break; 91324944Seric 91424944Seric case 'q': /* slope of queue only function */ 91524944Seric QueueFactor = atoi(val); 91624944Seric break; 91724944Seric 9188256Seric case 'Q': /* queue directory */ 9199381Seric if (val[0] == '\0') 9208269Seric QueueDir = "mqueue"; 9219381Seric else 9229381Seric QueueDir = newstr(val); 9238256Seric break; 9248256Seric 9258256Seric case 'r': /* read timeout */ 9269381Seric ReadTimeout = convtime(val); 9278256Seric break; 9288256Seric 9298256Seric case 'S': /* status file */ 9309381Seric if (val[0] == '\0') 9318269Seric StatFile = "sendmail.st"; 9329381Seric else 9339381Seric StatFile = newstr(val); 9348256Seric break; 9358256Seric 9368265Seric case 's': /* be super safe, even if expensive */ 9379381Seric SuperSafe = atobool(val); 9388256Seric break; 9398256Seric 9408256Seric case 'T': /* queue timeout */ 9419381Seric TimeOut = convtime(val); 94233936Sbostic /*FALLTHROUGH*/ 9438256Seric 9448265Seric case 't': /* time zone name */ 94552106Seric TimeZoneSpec = newstr(val); 9468265Seric break; 9478265Seric 94850556Seric case 'U': /* location of user database */ 94951360Seric UdbSpec = newstr(val); 95050556Seric break; 95150556Seric 9528256Seric case 'u': /* set default uid */ 95317474Seric DefUid = atoi(val); 95440973Sbostic setdefuser(); 9558256Seric break; 9568256Seric 9578269Seric case 'v': /* run in verbose mode */ 9589381Seric Verbose = atobool(val); 9598256Seric break; 9608256Seric 96151216Seric case 'w': /* we don't have wildcard MX records */ 96251216Seric NoWildcardMX = atobool(val); 96350537Seric break; 96450537Seric 96514879Seric case 'x': /* load avg at which to auto-queue msgs */ 96614879Seric QueueLA = atoi(val); 96714879Seric break; 96814879Seric 96914879Seric case 'X': /* load avg at which to auto-reject connections */ 97014879Seric RefuseLA = atoi(val); 97114879Seric break; 97214879Seric 97324981Seric case 'y': /* work recipient factor */ 97424981Seric WkRecipFact = atoi(val); 97524981Seric break; 97624981Seric 97724981Seric case 'Y': /* fork jobs during queue runs */ 97824952Seric ForkQueueRuns = atobool(val); 97924952Seric break; 98024952Seric 98124981Seric case 'z': /* work message class factor */ 98224981Seric WkClassFact = atoi(val); 98324981Seric break; 98424981Seric 98524981Seric case 'Z': /* work time factor */ 98624981Seric WkTimeFact = atoi(val); 98724981Seric break; 98824981Seric 9898256Seric default: 9908256Seric break; 9918256Seric } 99216878Seric if (sticky) 99316878Seric setbitn(opt, StickyOpt); 9949188Seric return; 9958256Seric } 99610687Seric /* 99710687Seric ** SETCLASS -- set a word into a class 99810687Seric ** 99910687Seric ** Parameters: 100010687Seric ** class -- the class to put the word in. 100110687Seric ** word -- the word to enter 100210687Seric ** 100310687Seric ** Returns: 100410687Seric ** none. 100510687Seric ** 100610687Seric ** Side Effects: 100710687Seric ** puts the word into the symbol table. 100810687Seric */ 100910687Seric 101010687Seric setclass(class, word) 101110687Seric int class; 101210687Seric char *word; 101310687Seric { 101410687Seric register STAB *s; 101510687Seric 101610687Seric s = stab(word, ST_CLASS, ST_ENTER); 101710687Seric setbitn(class, s->s_class); 101810687Seric } 1019