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*53400Seric static char sccsid[] = "@(#)readcf.c 5.36 (Berkeley) 05/10/92"; 1133731Sbostic #endif /* not lint */ 1222709Sdist 133313Seric # include "sendmail.h" 1452647Seric # 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(); 6652647Seric struct stat statb; 675909Seric char exbuf[MAXLINE]; 6816915Seric char pvpbuf[PSBUFSIZE]; 699350Seric extern char *fgetfolded(); 7010709Seric extern char *munchstring(); 713308Seric 7252647Seric FileName = cfname; 7352647Seric LineNumber = 0; 7452647Seric 753308Seric cf = fopen(cfname, "r"); 763308Seric if (cf == NULL) 773308Seric { 7852647Seric syserr("cannot open"); 793308Seric exit(EX_OSFILE); 803308Seric } 813308Seric 8252647Seric if (fstat(fileno(cf), &statb) < 0) 8352647Seric { 8452647Seric syserr("cannot fstat"); 8552647Seric exit(EX_OSFILE); 8652647Seric } 8752647Seric 8852647Seric if (!S_ISREG(statb.st_mode)) 8952647Seric { 9052647Seric syserr("not a plain file"); 9152647Seric exit(EX_OSFILE); 9252647Seric } 9352647Seric 9452647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 9552647Seric { 9653037Seric if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 9753037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 9853037Seric FileName); 9953037Seric #ifdef LOG 10053037Seric if (LogLevel > 0) 10153037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 10253037Seric FileName); 10353037Seric #endif 10452647Seric } 10552647Seric 1067854Seric while (fgetfolded(buf, sizeof buf, cf) != NULL) 1073308Seric { 10852637Seric if (buf[0] == '#') 10952637Seric continue; 11052637Seric 11116157Seric /* map $ into \001 (ASCII SOH) for macro expansion */ 11216157Seric for (p = buf; *p != '\0'; p++) 11316157Seric { 11452647Seric if (*p == '#' && p > buf && ConfigLevel >= 3) 11552647Seric { 11652647Seric /* this is an on-line comment */ 11752647Seric register char *e; 11852647Seric 11952647Seric switch (*--p) 12052647Seric { 12152647Seric case '\001': 12252647Seric /* it's from $# -- let it go through */ 12352647Seric p++; 12452647Seric break; 12552647Seric 12652647Seric case '\\': 12752647Seric /* it's backslash escaped */ 12852647Seric (void) strcpy(p, p + 1); 12952647Seric break; 13052647Seric 13152647Seric default: 13252647Seric /* delete preceeding white space */ 13352647Seric while (isspace(*p) && p > buf) 13452647Seric p--; 13552647Seric if ((e = index(++p, '\n')) != NULL) 13652647Seric (void) strcpy(p, e); 13752647Seric else 13852647Seric p[0] = p[1] = '\0'; 13952647Seric break; 14052647Seric } 14152647Seric continue; 14252647Seric } 14352647Seric 14416157Seric if (*p != '$') 14516157Seric continue; 14616157Seric 14716157Seric if (p[1] == '$') 14816157Seric { 14916157Seric /* actual dollar sign.... */ 15023111Seric (void) strcpy(p, p + 1); 15116157Seric continue; 15216157Seric } 15316157Seric 15416157Seric /* convert to macro expansion character */ 15516157Seric *p = '\001'; 15616157Seric } 15716157Seric 15816157Seric /* interpret this line */ 1593308Seric switch (buf[0]) 1603308Seric { 1613308Seric case '\0': 1623308Seric case '#': /* comment */ 1633308Seric break; 1643308Seric 1653308Seric case 'R': /* rewriting rule */ 1663308Seric for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 1673308Seric continue; 1683308Seric 1693308Seric if (*p == '\0') 1705909Seric { 1719381Seric syserr("invalid rewrite line \"%s\"", buf); 1725909Seric break; 1735909Seric } 1745909Seric 1755909Seric /* allocate space for the rule header */ 1765909Seric if (rwp == NULL) 1775909Seric { 1785909Seric RewriteRules[ruleset] = rwp = 1795909Seric (struct rewrite *) xalloc(sizeof *rwp); 1805909Seric } 1813308Seric else 1823308Seric { 1835909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 1845909Seric rwp = rwp->r_next; 1855909Seric } 1865909Seric rwp->r_next = NULL; 1873308Seric 1885909Seric /* expand and save the LHS */ 1895909Seric *p = '\0'; 1906991Seric expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv); 19116915Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf); 1925909Seric if (rwp->r_lhs != NULL) 1935909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 1945909Seric 1955909Seric /* expand and save the RHS */ 1965909Seric while (*++p == '\t') 1975909Seric continue; 1987231Seric q = p; 1997231Seric while (*p != '\0' && *p != '\t') 2007231Seric p++; 2017231Seric *p = '\0'; 2027231Seric expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv); 20316915Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf); 2045909Seric if (rwp->r_rhs != NULL) 2055909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 2063308Seric break; 2073308Seric 2084072Seric case 'S': /* select rewriting set */ 2094072Seric ruleset = atoi(&buf[1]); 2108056Seric if (ruleset >= MAXRWSETS || ruleset < 0) 2118056Seric { 2129381Seric syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 2138056Seric ruleset = 0; 2148056Seric } 2154072Seric rwp = NULL; 2164072Seric break; 2174072Seric 2183308Seric case 'D': /* macro definition */ 21910709Seric define(buf[1], newstr(munchstring(&buf[2])), CurEnv); 2203308Seric break; 2213308Seric 2223387Seric case 'H': /* required header line */ 2234088Seric (void) chompheader(&buf[1], TRUE); 2243387Seric break; 2253387Seric 2264061Seric case 'C': /* word class */ 2274432Seric case 'F': /* word class from file */ 2284432Seric /* read list of words from argument or file */ 2294432Seric if (buf[0] == 'F') 2304432Seric { 2314432Seric /* read from file */ 2324432Seric for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 2334432Seric continue; 2344432Seric if (*p == '\0') 2354432Seric p = "%s"; 2364432Seric else 2374432Seric { 2384432Seric *p = '\0'; 2394432Seric while (isspace(*++p)) 2404432Seric continue; 2414432Seric } 24210687Seric fileclass(buf[1], &buf[2], p); 2434432Seric break; 2444432Seric } 2454061Seric 2464432Seric /* scan the list of words and set class for all */ 2474061Seric for (p = &buf[2]; *p != '\0'; ) 2484061Seric { 2494061Seric register char *wd; 2504061Seric char delim; 2514061Seric 2524061Seric while (*p != '\0' && isspace(*p)) 2534061Seric p++; 2544061Seric wd = p; 2554061Seric while (*p != '\0' && !isspace(*p)) 2564061Seric p++; 2574061Seric delim = *p; 2584061Seric *p = '\0'; 2594061Seric if (wd[0] != '\0') 26010687Seric setclass(buf[1], wd); 2614061Seric *p = delim; 2624061Seric } 2634061Seric break; 2644061Seric 2654096Seric case 'M': /* define mailer */ 26621066Seric makemailer(&buf[1]); 2674096Seric break; 2684096Seric 2698252Seric case 'O': /* set option */ 27021755Seric setoption(buf[1], &buf[2], TRUE, FALSE); 2718252Seric break; 2728252Seric 2738252Seric case 'P': /* set precedence */ 2748252Seric if (NumPriorities >= MAXPRIORITIES) 2758252Seric { 2768547Seric toomany('P', MAXPRIORITIES); 2778252Seric break; 2788252Seric } 2799381Seric for (p = &buf[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 2808252Seric continue; 2818252Seric if (*p == '\0') 2828252Seric goto badline; 2838252Seric *p = '\0'; 2848252Seric Priorities[NumPriorities].pri_name = newstr(&buf[1]); 2858252Seric Priorities[NumPriorities].pri_val = atoi(++p); 2868252Seric NumPriorities++; 2878252Seric break; 2888252Seric 2898547Seric case 'T': /* trusted user(s) */ 2908547Seric p = &buf[1]; 2918547Seric while (*p != '\0') 2928547Seric { 2938547Seric while (isspace(*p)) 2948547Seric p++; 2958547Seric q = p; 2968547Seric while (*p != '\0' && !isspace(*p)) 2978547Seric p++; 2988547Seric if (*p != '\0') 2998547Seric *p++ = '\0'; 3008547Seric if (*q == '\0') 3018547Seric continue; 3028547Seric for (pv = TrustedUsers; *pv != NULL; pv++) 3038547Seric continue; 3048547Seric if (pv >= &TrustedUsers[MAXTRUST]) 3058547Seric { 3068547Seric toomany('T', MAXTRUST); 3078547Seric break; 3088547Seric } 3098547Seric *pv = newstr(q); 3108547Seric } 3118547Seric break; 3128547Seric 31352645Seric case 'V': /* configuration syntax version */ 31452645Seric ConfigLevel = atoi(&buf[1]); 31552645Seric break; 31652645Seric 3173308Seric default: 3184061Seric badline: 3199381Seric syserr("unknown control line \"%s\"", buf); 3203308Seric } 3213308Seric } 32252637Seric if (ferror(cf)) 32352637Seric { 32452647Seric syserr("I/O read error", cfname); 32552637Seric exit(EX_OSFILE); 32652637Seric } 32752637Seric fclose(cf); 3289381Seric FileName = NULL; 3294096Seric } 3304096Seric /* 3318547Seric ** TOOMANY -- signal too many of some option 3328547Seric ** 3338547Seric ** Parameters: 3348547Seric ** id -- the id of the error line 3358547Seric ** maxcnt -- the maximum possible values 3368547Seric ** 3378547Seric ** Returns: 3388547Seric ** none. 3398547Seric ** 3408547Seric ** Side Effects: 3418547Seric ** gives a syserr. 3428547Seric */ 3438547Seric 3448547Seric toomany(id, maxcnt) 3458547Seric char id; 3468547Seric int maxcnt; 3478547Seric { 3489381Seric syserr("too many %c lines, %d max", id, maxcnt); 3498547Seric } 3508547Seric /* 3514432Seric ** FILECLASS -- read members of a class from a file 3524432Seric ** 3534432Seric ** Parameters: 3544432Seric ** class -- class to define. 3554432Seric ** filename -- name of file to read. 3564432Seric ** fmt -- scanf string to use for match. 3574432Seric ** 3584432Seric ** Returns: 3594432Seric ** none 3604432Seric ** 3614432Seric ** Side Effects: 3624432Seric ** 3634432Seric ** puts all lines in filename that match a scanf into 3644432Seric ** the named class. 3654432Seric */ 3664432Seric 3674432Seric fileclass(class, filename, fmt) 3684432Seric int class; 3694432Seric char *filename; 3704432Seric char *fmt; 3714432Seric { 37225808Seric FILE *f; 3734432Seric char buf[MAXLINE]; 3744432Seric 37552062Seric if (filename[0] == '|') 37652062Seric f = popen(filename + 1, "r"); 37752062Seric else 37852062Seric f = fopen(filename, "r"); 3794432Seric if (f == NULL) 3804432Seric { 3814432Seric syserr("cannot open %s", filename); 3824432Seric return; 3834432Seric } 3844432Seric 3854432Seric while (fgets(buf, sizeof buf, f) != NULL) 3864432Seric { 3874432Seric register STAB *s; 38825808Seric register char *p; 38925808Seric # ifdef SCANF 3904432Seric char wordbuf[MAXNAME+1]; 3914432Seric 3924432Seric if (sscanf(buf, fmt, wordbuf) != 1) 3934432Seric continue; 39425808Seric p = wordbuf; 39525808Seric # else SCANF 39625808Seric p = buf; 39725808Seric # endif SCANF 39825808Seric 39925808Seric /* 40025808Seric ** Break up the match into words. 40125808Seric */ 40225808Seric 40325808Seric while (*p != '\0') 40425808Seric { 40525808Seric register char *q; 40625808Seric 40725808Seric /* strip leading spaces */ 40825808Seric while (isspace(*p)) 40925808Seric p++; 41025808Seric if (*p == '\0') 41125808Seric break; 41225808Seric 41325808Seric /* find the end of the word */ 41425808Seric q = p; 41525808Seric while (*p != '\0' && !isspace(*p)) 41625808Seric p++; 41725808Seric if (*p != '\0') 41825808Seric *p++ = '\0'; 41925808Seric 42025808Seric /* enter the word in the symbol table */ 42125808Seric s = stab(q, ST_CLASS, ST_ENTER); 42225808Seric setbitn(class, s->s_class); 42325808Seric } 4244432Seric } 4254432Seric 42652062Seric if (filename[0] == '|') 42752062Seric (void) pclose(f); 42852062Seric else 42952062Seric (void) fclose(f); 4304432Seric } 4314432Seric /* 4324096Seric ** MAKEMAILER -- define a new mailer. 4334096Seric ** 4344096Seric ** Parameters: 43510327Seric ** line -- description of mailer. This is in labeled 43610327Seric ** fields. The fields are: 43710327Seric ** P -- the path to the mailer 43810327Seric ** F -- the flags associated with the mailer 43910327Seric ** A -- the argv for this mailer 44010327Seric ** S -- the sender rewriting set 44110327Seric ** R -- the recipient rewriting set 44210327Seric ** E -- the eol string 44310327Seric ** The first word is the canonical name of the mailer. 4444096Seric ** 4454096Seric ** Returns: 4464096Seric ** none. 4474096Seric ** 4484096Seric ** Side Effects: 4494096Seric ** enters the mailer into the mailer table. 4504096Seric */ 4513308Seric 45221066Seric makemailer(line) 4534096Seric char *line; 4544096Seric { 4554096Seric register char *p; 4568067Seric register struct mailer *m; 4578067Seric register STAB *s; 4588067Seric int i; 45910327Seric char fcode; 4604096Seric extern int NextMailer; 46110327Seric extern char **makeargv(); 46210327Seric extern char *munchstring(); 46310327Seric extern char *DelimChar; 46410701Seric extern long atol(); 4654096Seric 46610327Seric /* allocate a mailer and set up defaults */ 46710327Seric m = (struct mailer *) xalloc(sizeof *m); 46810327Seric bzero((char *) m, sizeof *m); 46910327Seric m->m_mno = NextMailer; 47010327Seric m->m_eol = "\n"; 47110327Seric 47210327Seric /* collect the mailer name */ 47310327Seric for (p = line; *p != '\0' && *p != ',' && !isspace(*p); p++) 47410327Seric continue; 47510327Seric if (*p != '\0') 47610327Seric *p++ = '\0'; 47710327Seric m->m_name = newstr(line); 47810327Seric 47910327Seric /* now scan through and assign info from the fields */ 48010327Seric while (*p != '\0') 48110327Seric { 48210327Seric while (*p != '\0' && (*p == ',' || isspace(*p))) 48310327Seric p++; 48410327Seric 48510327Seric /* p now points to field code */ 48610327Seric fcode = *p; 48710327Seric while (*p != '\0' && *p != '=' && *p != ',') 48810327Seric p++; 48910327Seric if (*p++ != '=') 49010327Seric { 49152637Seric syserr("mailer %s: `=' expected", m->m_name); 49210327Seric return; 49310327Seric } 49410327Seric while (isspace(*p)) 49510327Seric p++; 49610327Seric 49710327Seric /* p now points to the field body */ 49810327Seric p = munchstring(p); 49910327Seric 50010327Seric /* install the field into the mailer struct */ 50110327Seric switch (fcode) 50210327Seric { 50310327Seric case 'P': /* pathname */ 50410327Seric m->m_mailer = newstr(p); 50510327Seric break; 50610327Seric 50710327Seric case 'F': /* flags */ 50810687Seric for (; *p != '\0'; p++) 50952637Seric if (!isspace(*p)) 51052637Seric setbitn(*p, m->m_flags); 51110327Seric break; 51210327Seric 51310327Seric case 'S': /* sender rewriting ruleset */ 51410327Seric case 'R': /* recipient rewriting ruleset */ 51510327Seric i = atoi(p); 51610327Seric if (i < 0 || i >= MAXRWSETS) 51710327Seric { 51810327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 51910327Seric return; 52010327Seric } 52110327Seric if (fcode == 'S') 52210327Seric m->m_s_rwset = i; 52310327Seric else 52410327Seric m->m_r_rwset = i; 52510327Seric break; 52610327Seric 52710327Seric case 'E': /* end of line string */ 52810327Seric m->m_eol = newstr(p); 52910327Seric break; 53010327Seric 53110327Seric case 'A': /* argument vector */ 53210327Seric m->m_argv = makeargv(p); 53310327Seric break; 53410701Seric 53510701Seric case 'M': /* maximum message size */ 53610701Seric m->m_maxsize = atol(p); 53710701Seric break; 53852106Seric 53952106Seric case 'L': /* maximum line length */ 54052106Seric m->m_linelimit = atoi(p); 54152106Seric break; 54210327Seric } 54310327Seric 54410327Seric p = DelimChar; 54510327Seric } 54610327Seric 54752106Seric /* do some heuristic cleanup for back compatibility */ 54852106Seric if (bitnset(M_LIMITS, m->m_flags)) 54952106Seric { 55052106Seric if (m->m_linelimit == 0) 55152106Seric m->m_linelimit = SMTPLINELIM; 55252106Seric if (!bitnset(M_8BITS, m->m_flags)) 55352106Seric setbitn(M_7BITS, m->m_flags); 55452106Seric } 55552106Seric 55610327Seric /* now store the mailer away */ 5574096Seric if (NextMailer >= MAXMAILERS) 5584096Seric { 5599381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 5604096Seric return; 5614096Seric } 56210327Seric Mailer[NextMailer++] = m; 56310327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 56410327Seric s->s_mailer = m; 56510327Seric } 56610327Seric /* 56710327Seric ** MUNCHSTRING -- translate a string into internal form. 56810327Seric ** 56910327Seric ** Parameters: 57010327Seric ** p -- the string to munch. 57110327Seric ** 57210327Seric ** Returns: 57310327Seric ** the munched string. 57410327Seric ** 57510327Seric ** Side Effects: 57610327Seric ** Sets "DelimChar" to point to the string that caused us 57710327Seric ** to stop. 57810327Seric */ 5794096Seric 58010327Seric char * 58110327Seric munchstring(p) 58210327Seric register char *p; 58310327Seric { 58410327Seric register char *q; 58510327Seric bool backslash = FALSE; 58610327Seric bool quotemode = FALSE; 58710327Seric static char buf[MAXLINE]; 58810327Seric extern char *DelimChar; 5894096Seric 59010327Seric for (q = buf; *p != '\0'; p++) 5914096Seric { 59210327Seric if (backslash) 59310327Seric { 59410327Seric /* everything is roughly literal */ 59510357Seric backslash = FALSE; 59610327Seric switch (*p) 59710327Seric { 59810327Seric case 'r': /* carriage return */ 59910327Seric *q++ = '\r'; 60010327Seric continue; 60110327Seric 60210327Seric case 'n': /* newline */ 60310327Seric *q++ = '\n'; 60410327Seric continue; 60510327Seric 60610327Seric case 'f': /* form feed */ 60710327Seric *q++ = '\f'; 60810327Seric continue; 60910327Seric 61010327Seric case 'b': /* backspace */ 61110327Seric *q++ = '\b'; 61210327Seric continue; 61310327Seric } 61410327Seric *q++ = *p; 61510327Seric } 61610327Seric else 61710327Seric { 61810327Seric if (*p == '\\') 61910327Seric backslash = TRUE; 62010327Seric else if (*p == '"') 62110327Seric quotemode = !quotemode; 62210327Seric else if (quotemode || *p != ',') 62310327Seric *q++ = *p; 62410327Seric else 62510327Seric break; 62610327Seric } 6274096Seric } 6284096Seric 62910327Seric DelimChar = p; 63010327Seric *q++ = '\0'; 63110327Seric return (buf); 63210327Seric } 63310327Seric /* 63410327Seric ** MAKEARGV -- break up a string into words 63510327Seric ** 63610327Seric ** Parameters: 63710327Seric ** p -- the string to break up. 63810327Seric ** 63910327Seric ** Returns: 64010327Seric ** a char **argv (dynamically allocated) 64110327Seric ** 64210327Seric ** Side Effects: 64310327Seric ** munges p. 64410327Seric */ 6454096Seric 64610327Seric char ** 64710327Seric makeargv(p) 64810327Seric register char *p; 64910327Seric { 65010327Seric char *q; 65110327Seric int i; 65210327Seric char **avp; 65310327Seric char *argv[MAXPV + 1]; 65410327Seric 65510327Seric /* take apart the words */ 65610327Seric i = 0; 65710327Seric while (*p != '\0' && i < MAXPV) 6584096Seric { 65910327Seric q = p; 66010327Seric while (*p != '\0' && !isspace(*p)) 66110327Seric p++; 66210327Seric while (isspace(*p)) 66310327Seric *p++ = '\0'; 66410327Seric argv[i++] = newstr(q); 6654096Seric } 66610327Seric argv[i++] = NULL; 6674096Seric 66810327Seric /* now make a copy of the argv */ 66910327Seric avp = (char **) xalloc(sizeof *avp * i); 67016893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 67110327Seric 67210327Seric return (avp); 6733308Seric } 6743308Seric /* 6753308Seric ** PRINTRULES -- print rewrite rules (for debugging) 6763308Seric ** 6773308Seric ** Parameters: 6783308Seric ** none. 6793308Seric ** 6803308Seric ** Returns: 6813308Seric ** none. 6823308Seric ** 6833308Seric ** Side Effects: 6843308Seric ** prints rewrite rules. 6853308Seric */ 6863308Seric 6873308Seric printrules() 6883308Seric { 6893308Seric register struct rewrite *rwp; 6904072Seric register int ruleset; 6913308Seric 6924072Seric for (ruleset = 0; ruleset < 10; ruleset++) 6933308Seric { 6944072Seric if (RewriteRules[ruleset] == NULL) 6954072Seric continue; 6968067Seric printf("\n----Rule Set %d:", ruleset); 6973308Seric 6984072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 6993308Seric { 7008067Seric printf("\nLHS:"); 7018067Seric printav(rwp->r_lhs); 7028067Seric printf("RHS:"); 7038067Seric printav(rwp->r_rhs); 7043308Seric } 7053308Seric } 7063308Seric } 7074319Seric 7084096Seric /* 7098256Seric ** SETOPTION -- set global processing option 7108256Seric ** 7118256Seric ** Parameters: 7128256Seric ** opt -- option name. 7138256Seric ** val -- option value (as a text string). 71421755Seric ** safe -- set if this came from a configuration file. 71521755Seric ** Some options (if set from the command line) will 71621755Seric ** reset the user id to avoid security problems. 7178269Seric ** sticky -- if set, don't let other setoptions override 7188269Seric ** this value. 7198256Seric ** 7208256Seric ** Returns: 7218256Seric ** none. 7228256Seric ** 7238256Seric ** Side Effects: 7248256Seric ** Sets options as implied by the arguments. 7258256Seric */ 7268256Seric 72710687Seric static BITMAP StickyOpt; /* set if option is stuck */ 7288269Seric 72921755Seric setoption(opt, val, safe, sticky) 7308256Seric char opt; 7318256Seric char *val; 73221755Seric bool safe; 7338269Seric bool sticky; 7348256Seric { 7358265Seric extern bool atobool(); 73612633Seric extern time_t convtime(); 73714879Seric extern int QueueLA; 73814879Seric extern int RefuseLA; 73917474Seric extern bool trusteduser(); 74017474Seric extern char *username(); 7418256Seric 7428256Seric if (tTd(37, 1)) 7439341Seric printf("setoption %c=%s", opt, val); 7448256Seric 7458256Seric /* 7468269Seric ** See if this option is preset for us. 7478256Seric */ 7488256Seric 74910687Seric if (bitnset(opt, StickyOpt)) 7508269Seric { 7519341Seric if (tTd(37, 1)) 7529341Seric printf(" (ignored)\n"); 7538269Seric return; 7548269Seric } 7558269Seric 75621755Seric /* 75721755Seric ** Check to see if this option can be specified by this user. 75821755Seric */ 75921755Seric 76036238Skarels if (!safe && getuid() == 0) 76121755Seric safe = TRUE; 762*53400Seric if (!safe && index("deiLmorsvC", opt) == NULL) 76321755Seric { 76439111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 76521755Seric { 76636582Sbostic if (tTd(37, 1)) 76736582Sbostic printf(" (unsafe)"); 76836582Sbostic if (getuid() != geteuid()) 76936582Sbostic { 77051210Seric if (tTd(37, 1)) 77151210Seric printf("(Resetting uid)"); 77236582Sbostic (void) setgid(getgid()); 77336582Sbostic (void) setuid(getuid()); 77436582Sbostic } 77521755Seric } 77621755Seric } 77751210Seric if (tTd(37, 1)) 77817985Seric printf("\n"); 7798269Seric 7808256Seric switch (opt) 7818256Seric { 78251312Seric case '=': /* config file generation level */ 78351312Seric ConfigLevel = atoi(val); 78451312Seric break; 78551312Seric 78652106Seric case '8': /* allow eight-bit input */ 78752106Seric EightBit = atobool(val); 78852106Seric break; 78952106Seric 7908256Seric case 'A': /* set default alias file */ 7919381Seric if (val[0] == '\0') 7928269Seric AliasFile = "aliases"; 7939381Seric else 7949381Seric AliasFile = newstr(val); 7958256Seric break; 7968256Seric 79717474Seric case 'a': /* look N minutes for "@:@" in alias file */ 79817474Seric if (val[0] == '\0') 79917474Seric SafeAlias = 5; 80017474Seric else 80117474Seric SafeAlias = atoi(val); 80217474Seric break; 80317474Seric 80416843Seric case 'B': /* substitution for blank character */ 80516843Seric SpaceSub = val[0]; 80616843Seric if (SpaceSub == '\0') 80716843Seric SpaceSub = ' '; 80816843Seric break; 80916843Seric 8109284Seric case 'c': /* don't connect to "expensive" mailers */ 8119381Seric NoConnect = atobool(val); 8129284Seric break; 8139284Seric 81451305Seric case 'C': /* checkpoint every N addresses */ 81551305Seric CheckpointInterval = atoi(val); 81624944Seric break; 81724944Seric 8189284Seric case 'd': /* delivery mode */ 8199284Seric switch (*val) 8208269Seric { 8219284Seric case '\0': 8229284Seric SendMode = SM_DELIVER; 8238269Seric break; 8248269Seric 82510755Seric case SM_QUEUE: /* queue only */ 82610755Seric #ifndef QUEUE 82710755Seric syserr("need QUEUE to set -odqueue"); 82810755Seric #endif QUEUE 82910755Seric /* fall through..... */ 83010755Seric 8319284Seric case SM_DELIVER: /* do everything */ 8329284Seric case SM_FORK: /* fork after verification */ 8339284Seric SendMode = *val; 8348269Seric break; 8358269Seric 8368269Seric default: 8379284Seric syserr("Unknown delivery mode %c", *val); 8388269Seric exit(EX_USAGE); 8398269Seric } 8408269Seric break; 8418269Seric 8429146Seric case 'D': /* rebuild alias database as needed */ 8439381Seric AutoRebuild = atobool(val); 8449146Seric break; 8459146Seric 8468269Seric case 'e': /* set error processing mode */ 8478269Seric switch (*val) 8488269Seric { 8499381Seric case EM_QUIET: /* be silent about it */ 8509381Seric case EM_MAIL: /* mail back */ 8519381Seric case EM_BERKNET: /* do berknet error processing */ 8529381Seric case EM_WRITE: /* write back (or mail) */ 8538269Seric HoldErrs = TRUE; 8549381Seric /* fall through... */ 8558269Seric 8569381Seric case EM_PRINT: /* print errors normally (default) */ 8579381Seric ErrorMode = *val; 8588269Seric break; 8598269Seric } 8608269Seric break; 8618269Seric 8629049Seric case 'F': /* file mode */ 86317975Seric FileMode = atooct(val) & 0777; 8649049Seric break; 8659049Seric 8668269Seric case 'f': /* save Unix-style From lines on front */ 8679381Seric SaveFrom = atobool(val); 8688269Seric break; 8698269Seric 8708256Seric case 'g': /* default gid */ 87117474Seric DefGid = atoi(val); 8728256Seric break; 8738256Seric 8748256Seric case 'H': /* help file */ 8759381Seric if (val[0] == '\0') 8768269Seric HelpFile = "sendmail.hf"; 8779381Seric else 8789381Seric HelpFile = newstr(val); 8798256Seric break; 8808256Seric 88151305Seric case 'h': /* maximum hop count */ 88251305Seric MaxHopCount = atoi(val); 88351305Seric break; 88451305Seric 88535651Seric case 'I': /* use internet domain name server */ 88635651Seric UseNameServer = atobool(val); 88735651Seric break; 88835651Seric 8898269Seric case 'i': /* ignore dot lines in message */ 8909381Seric IgnrDot = atobool(val); 8918269Seric break; 8928269Seric 8938256Seric case 'L': /* log level */ 8949381Seric LogLevel = atoi(val); 8958256Seric break; 8968256Seric 8978269Seric case 'M': /* define macro */ 8989381Seric define(val[0], newstr(&val[1]), CurEnv); 89916878Seric sticky = FALSE; 9008269Seric break; 9018269Seric 9028269Seric case 'm': /* send to me too */ 9039381Seric MeToo = atobool(val); 9048269Seric break; 9058269Seric 90625820Seric case 'n': /* validate RHS in newaliases */ 90725820Seric CheckAliases = atobool(val); 90825820Seric break; 90925820Seric 9108269Seric case 'o': /* assume old style headers */ 9119381Seric if (atobool(val)) 9129341Seric CurEnv->e_flags |= EF_OLDSTYLE; 9139341Seric else 9149341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 9158269Seric break; 9168269Seric 91724944Seric case 'P': /* postmaster copy address for returned mail */ 91824944Seric PostMasterCopy = newstr(val); 91924944Seric break; 92024944Seric 92124944Seric case 'q': /* slope of queue only function */ 92224944Seric QueueFactor = atoi(val); 92324944Seric break; 92424944Seric 9258256Seric case 'Q': /* queue directory */ 9269381Seric if (val[0] == '\0') 9278269Seric QueueDir = "mqueue"; 9289381Seric else 9299381Seric QueueDir = newstr(val); 9308256Seric break; 9318256Seric 9328256Seric case 'r': /* read timeout */ 9339381Seric ReadTimeout = convtime(val); 9348256Seric break; 9358256Seric 9368256Seric case 'S': /* status file */ 9379381Seric if (val[0] == '\0') 9388269Seric StatFile = "sendmail.st"; 9399381Seric else 9409381Seric StatFile = newstr(val); 9418256Seric break; 9428256Seric 9438265Seric case 's': /* be super safe, even if expensive */ 9449381Seric SuperSafe = atobool(val); 9458256Seric break; 9468256Seric 9478256Seric case 'T': /* queue timeout */ 9489381Seric TimeOut = convtime(val); 94933936Sbostic /*FALLTHROUGH*/ 9508256Seric 9518265Seric case 't': /* time zone name */ 95252106Seric TimeZoneSpec = newstr(val); 9538265Seric break; 9548265Seric 95550556Seric case 'U': /* location of user database */ 95651360Seric UdbSpec = newstr(val); 95750556Seric break; 95850556Seric 9598256Seric case 'u': /* set default uid */ 96017474Seric DefUid = atoi(val); 96140973Sbostic setdefuser(); 9628256Seric break; 9638256Seric 9648269Seric case 'v': /* run in verbose mode */ 9659381Seric Verbose = atobool(val); 9668256Seric break; 9678256Seric 96851216Seric case 'w': /* we don't have wildcard MX records */ 96951216Seric NoWildcardMX = atobool(val); 97050537Seric break; 97150537Seric 97214879Seric case 'x': /* load avg at which to auto-queue msgs */ 97314879Seric QueueLA = atoi(val); 97414879Seric break; 97514879Seric 97614879Seric case 'X': /* load avg at which to auto-reject connections */ 97714879Seric RefuseLA = atoi(val); 97814879Seric break; 97914879Seric 98024981Seric case 'y': /* work recipient factor */ 98124981Seric WkRecipFact = atoi(val); 98224981Seric break; 98324981Seric 98424981Seric case 'Y': /* fork jobs during queue runs */ 98524952Seric ForkQueueRuns = atobool(val); 98624952Seric break; 98724952Seric 98824981Seric case 'z': /* work message class factor */ 98924981Seric WkClassFact = atoi(val); 99024981Seric break; 99124981Seric 99224981Seric case 'Z': /* work time factor */ 99324981Seric WkTimeFact = atoi(val); 99424981Seric break; 99524981Seric 9968256Seric default: 9978256Seric break; 9988256Seric } 99916878Seric if (sticky) 100016878Seric setbitn(opt, StickyOpt); 10019188Seric return; 10028256Seric } 100310687Seric /* 100410687Seric ** SETCLASS -- set a word into a class 100510687Seric ** 100610687Seric ** Parameters: 100710687Seric ** class -- the class to put the word in. 100810687Seric ** word -- the word to enter 100910687Seric ** 101010687Seric ** Returns: 101110687Seric ** none. 101210687Seric ** 101310687Seric ** Side Effects: 101410687Seric ** puts the word into the symbol table. 101510687Seric */ 101610687Seric 101710687Seric setclass(class, word) 101810687Seric int class; 101910687Seric char *word; 102010687Seric { 102110687Seric register STAB *s; 102210687Seric 102310687Seric s = stab(word, ST_CLASS, ST_ENTER); 102410687Seric setbitn(class, s->s_class); 102510687Seric } 1026