13313Seric # include "sendmail.h" 23308Seric 3*8265Seric SCCSID(@(#)readcf.c 3.34 09/26/82); 43308Seric 53308Seric /* 63308Seric ** READCF -- read control file. 73308Seric ** 83308Seric ** This routine reads the control file and builds the internal 93308Seric ** form. 103308Seric ** 114432Seric ** The file is formatted as a sequence of lines, each taken 124432Seric ** atomically. The first character of each line describes how 134432Seric ** the line is to be interpreted. The lines are: 144432Seric ** Dxval Define macro x to have value val. 154432Seric ** Cxword Put word into class x. 164432Seric ** Fxfile [fmt] Read file for lines to put into 174432Seric ** class x. Use scanf string 'fmt' 184432Seric ** or "%s" if not present. Fmt should 194432Seric ** only produce one string-valued result. 204432Seric ** Hname: value Define header with field-name 'name' 214432Seric ** and value as specified; this will be 224432Seric ** macro expanded immediately before 234432Seric ** use. 244432Seric ** Sn Use rewriting set n. 254432Seric ** Rlhs rhs Rewrite addresses that match lhs to 264432Seric ** be rhs. 278252Seric ** Mn p f s r a Define mailer. n - internal name, 288252Seric ** p - pathname, f - flags, s - rewriting 298252Seric ** ruleset for sender, s - rewriting ruleset 308252Seric ** for recipients, a - argument vector. 318252Seric ** Oxvalue Set option x to value. 328252Seric ** Pname=value Set precedence name to value. 334432Seric ** 343308Seric ** Parameters: 353308Seric ** cfname -- control file name. 364217Seric ** safe -- set if this is a system configuration file. 374217Seric ** Non-system configuration files can not do 384217Seric ** certain things (e.g., leave the SUID bit on 394217Seric ** when executing mailers). 403308Seric ** 413308Seric ** Returns: 423308Seric ** none. 433308Seric ** 443308Seric ** Side Effects: 453308Seric ** Builds several internal tables. 463308Seric */ 473308Seric 484217Seric readcf(cfname, safe) 493308Seric char *cfname; 504217Seric bool safe; 513308Seric { 523308Seric FILE *cf; 533308Seric char buf[MAXLINE]; 543308Seric register char *p; 553308Seric struct rewrite *rwp = NULL; 563308Seric extern char **prescan(); 573308Seric extern char **copyplist(); 584061Seric int class; 594072Seric int ruleset = 0; 605909Seric char exbuf[MAXLINE]; 617231Seric char *q; 623308Seric 633308Seric cf = fopen(cfname, "r"); 643308Seric if (cf == NULL) 653308Seric { 663308Seric syserr("cannot open %s", cfname); 673308Seric exit(EX_OSFILE); 683308Seric } 693308Seric 708056Seric LineNumber = 0; 717854Seric while (fgetfolded(buf, sizeof buf, cf) != NULL) 723308Seric { 733308Seric switch (buf[0]) 743308Seric { 753308Seric case '\0': 763308Seric case '#': /* comment */ 773308Seric break; 783308Seric 793308Seric case 'R': /* rewriting rule */ 803308Seric for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 813308Seric continue; 823308Seric 833308Seric if (*p == '\0') 845909Seric { 858056Seric syserr("line %d: invalid rewrite line \"%s\"", 868056Seric LineNumber, buf); 875909Seric break; 885909Seric } 895909Seric 905909Seric /* allocate space for the rule header */ 915909Seric if (rwp == NULL) 925909Seric { 935909Seric RewriteRules[ruleset] = rwp = 945909Seric (struct rewrite *) xalloc(sizeof *rwp); 955909Seric } 963308Seric else 973308Seric { 985909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 995909Seric rwp = rwp->r_next; 1005909Seric } 1015909Seric rwp->r_next = NULL; 1023308Seric 1035909Seric /* expand and save the LHS */ 1045909Seric *p = '\0'; 1056991Seric expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv); 1065909Seric rwp->r_lhs = prescan(exbuf, '\t'); 1075909Seric if (rwp->r_lhs != NULL) 1085909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 1095909Seric 1105909Seric /* expand and save the RHS */ 1115909Seric while (*++p == '\t') 1125909Seric continue; 1137231Seric q = p; 1147231Seric while (*p != '\0' && *p != '\t') 1157231Seric p++; 1167231Seric *p = '\0'; 1177231Seric expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv); 1185909Seric rwp->r_rhs = prescan(exbuf, '\t'); 1195909Seric if (rwp->r_rhs != NULL) 1205909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 1213308Seric break; 1223308Seric 1234072Seric case 'S': /* select rewriting set */ 1244072Seric ruleset = atoi(&buf[1]); 1258056Seric if (ruleset >= MAXRWSETS || ruleset < 0) 1268056Seric { 1278056Seric syserr("readcf: line %d: bad ruleset %d (%d max)", 1288056Seric LineNumber, ruleset, MAXRWSETS); 1298056Seric ruleset = 0; 1308056Seric } 1314072Seric rwp = NULL; 1324072Seric break; 1334072Seric 1343308Seric case 'D': /* macro definition */ 1353308Seric define(buf[1], newstr(&buf[2])); 1363308Seric break; 1373308Seric 1383387Seric case 'H': /* required header line */ 1394088Seric (void) chompheader(&buf[1], TRUE); 1403387Seric break; 1413387Seric 1424061Seric case 'C': /* word class */ 1434432Seric case 'F': /* word class from file */ 1444061Seric class = buf[1]; 1454061Seric if (!isalpha(class)) 1464061Seric goto badline; 1474061Seric if (isupper(class)) 1484061Seric class -= 'A'; 1494061Seric else 1504061Seric class -= 'a'; 1514432Seric 1524432Seric /* read list of words from argument or file */ 1534432Seric if (buf[0] == 'F') 1544432Seric { 1554432Seric /* read from file */ 1564432Seric for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 1574432Seric continue; 1584432Seric if (*p == '\0') 1594432Seric p = "%s"; 1604432Seric else 1614432Seric { 1624432Seric *p = '\0'; 1634432Seric while (isspace(*++p)) 1644432Seric continue; 1654432Seric } 1664432Seric fileclass(class, &buf[2], p); 1674432Seric break; 1684432Seric } 1694061Seric 1704432Seric /* scan the list of words and set class for all */ 1714061Seric for (p = &buf[2]; *p != '\0'; ) 1724061Seric { 1734061Seric register char *wd; 1744061Seric char delim; 1754061Seric register STAB *s; 1764061Seric 1774061Seric while (*p != '\0' && isspace(*p)) 1784061Seric p++; 1794061Seric wd = p; 1804061Seric while (*p != '\0' && !isspace(*p)) 1814061Seric p++; 1824061Seric delim = *p; 1834061Seric *p = '\0'; 1844061Seric if (wd[0] != '\0') 1854061Seric { 1864103Seric s = stab(wd, ST_CLASS, ST_ENTER); 1876275Seric s->s_class |= 1L << class; 1884061Seric } 1894061Seric *p = delim; 1904061Seric } 1914061Seric break; 1924061Seric 1934096Seric case 'M': /* define mailer */ 1944217Seric makemailer(&buf[1], safe); 1954096Seric break; 1964096Seric 1978252Seric case 'O': /* set option */ 1988256Seric setoption(buf[1], &buf[2]); 1998252Seric break; 2008252Seric 2018252Seric case 'P': /* set precedence */ 2028252Seric if (NumPriorities >= MAXPRIORITIES) 2038252Seric { 2048252Seric syserr("readcf: line %d: too many P lines, %d max", 2058252Seric LineNumber, MAXPRIORITIES); 2068252Seric break; 2078252Seric } 2088252Seric for (p = &buf[1]; *p != '\0' && *p != '='; p++) 2098252Seric continue; 2108252Seric if (*p == '\0') 2118252Seric goto badline; 2128252Seric *p = '\0'; 2138252Seric Priorities[NumPriorities].pri_name = newstr(&buf[1]); 2148252Seric Priorities[NumPriorities].pri_val = atoi(++p); 2158252Seric NumPriorities++; 2168252Seric break; 2178252Seric 2183308Seric default: 2194061Seric badline: 2208056Seric syserr("readcf: line %d: unknown control line \"%s\"", 2218056Seric LineNumber, buf); 2223308Seric } 2233308Seric } 2244096Seric } 2254096Seric /* 2264432Seric ** FILECLASS -- read members of a class from a file 2274432Seric ** 2284432Seric ** Parameters: 2294432Seric ** class -- class to define. 2304432Seric ** filename -- name of file to read. 2314432Seric ** fmt -- scanf string to use for match. 2324432Seric ** 2334432Seric ** Returns: 2344432Seric ** none 2354432Seric ** 2364432Seric ** Side Effects: 2374432Seric ** 2384432Seric ** puts all lines in filename that match a scanf into 2394432Seric ** the named class. 2404432Seric */ 2414432Seric 2424432Seric fileclass(class, filename, fmt) 2434432Seric int class; 2444432Seric char *filename; 2454432Seric char *fmt; 2464432Seric { 2474432Seric register FILE *f; 2484432Seric char buf[MAXLINE]; 2494432Seric 2504432Seric f = fopen(filename, "r"); 2514432Seric if (f == NULL) 2524432Seric { 2534432Seric syserr("cannot open %s", filename); 2544432Seric return; 2554432Seric } 2564432Seric 2574432Seric while (fgets(buf, sizeof buf, f) != NULL) 2584432Seric { 2594432Seric register STAB *s; 2604432Seric char wordbuf[MAXNAME+1]; 2614432Seric 2624432Seric if (sscanf(buf, fmt, wordbuf) != 1) 2634432Seric continue; 2644432Seric s = stab(wordbuf, ST_CLASS, ST_ENTER); 2656275Seric s->s_class |= 1L << class; 2664432Seric } 2674432Seric 2684627Seric (void) fclose(f); 2694432Seric } 2704432Seric /* 2714096Seric ** MAKEMAILER -- define a new mailer. 2724096Seric ** 2734096Seric ** Parameters: 2744096Seric ** line -- description of mailer. This is in tokens 2754096Seric ** separated by white space. The fields are: 2764096Seric ** * the name of the mailer, as refered to 2774096Seric ** in the rewriting rules. 2784096Seric ** * the pathname of the program to fork to 2794096Seric ** execute it. 2804096Seric ** * the options needed by this program. 2814096Seric ** * the macro string needed to translate 2824096Seric ** a local "from" name to one that can be 2834096Seric ** returned to this machine. 2844096Seric ** * the argument vector (a series of parameters). 2854217Seric ** safe -- set if this is a safe configuration file. 2864096Seric ** 2874096Seric ** Returns: 2884096Seric ** none. 2894096Seric ** 2904096Seric ** Side Effects: 2914096Seric ** enters the mailer into the mailer table. 2924096Seric */ 2933308Seric 2944096Seric # define SETWORD \ 2954096Seric { \ 2964096Seric while (*p != '\0' && isspace(*p)) \ 2974096Seric p++; \ 2984096Seric q = p; \ 2994096Seric while (*p != '\0' && !isspace(*p)) \ 3004096Seric p++; \ 3014096Seric if (*p != '\0') \ 3024096Seric *p++ = '\0'; \ 3034096Seric } 3044096Seric 3054217Seric makemailer(line, safe) 3064096Seric char *line; 3074217Seric bool safe; 3084096Seric { 3094096Seric register char *p; 3104096Seric register char *q; 3118067Seric register struct mailer *m; 3128067Seric register STAB *s; 3138067Seric int i; 3144096Seric char *mname; 3154096Seric char *mpath; 3164627Seric u_long mopts; 3178067Seric short mrset, msset; 3188067Seric char *margv[MAXPV + 1]; 3194627Seric extern u_long mfencode(); 3204096Seric extern int NextMailer; 3214096Seric 3224096Seric if (NextMailer >= MAXMAILERS) 3234096Seric { 3248056Seric syserr("readcf: line %d: too many mailers defined (%d max)", 3258056Seric LineNumber, MAXMAILERS); 3264096Seric return; 3274096Seric } 3284096Seric 3294096Seric /* collect initial information */ 3304096Seric p = line; 3314096Seric SETWORD; 3324096Seric mname = q; 3334096Seric SETWORD; 3344096Seric mpath = q; 3354096Seric SETWORD; 3364627Seric mopts = mfencode(q); 3374217Seric if (!safe) 3384217Seric mopts &= ~M_RESTR; 3394096Seric SETWORD; 3408067Seric msset = atoi(q); 3418067Seric SETWORD; 3428067Seric mrset = atoi(q); 3434096Seric 3444096Seric if (*p == '\0') 3454096Seric { 3468056Seric syserr("readcf: line %d: invalid M line in configuration file", 3478056Seric LineNumber); 3484096Seric return; 3494096Seric } 3508067Seric if (msset >= MAXRWSETS || mrset >= MAXRWSETS) 3518067Seric { 3528067Seric syserr("readcf: line %d: invalid rewrite set, %d max", 3538067Seric LineNumber, MAXRWSETS); 3548067Seric return; 3558067Seric } 3564096Seric 3574096Seric /* allocate a mailer */ 3584096Seric m = (struct mailer *) xalloc(sizeof *m); 3594096Seric m->m_name = newstr(mname); 3604096Seric m->m_mailer = newstr(mpath); 3614096Seric m->m_flags = mopts; 3628067Seric m->m_r_rwset = mrset; 3638067Seric m->m_s_rwset = msset; 3644096Seric m->m_badstat = EX_UNAVAILABLE; 3654439Seric m->m_mno = NextMailer; 3664096Seric Mailer[NextMailer++] = m; 3674096Seric 3684096Seric /* collect the argument vector */ 3694096Seric for (i = 0; i < MAXPV - 1 && *p != '\0'; i++) 3704096Seric { 3714096Seric SETWORD; 3724096Seric margv[i] = newstr(q); 3734096Seric } 3744096Seric margv[i++] = NULL; 3754096Seric 3764096Seric /* save the argv */ 3777009Seric m->m_argv = (char **) xalloc(sizeof margv[0] * i); 3784096Seric bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i); 3794439Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 3804439Seric s->s_mailer = m; 3813308Seric } 3823308Seric /* 3833308Seric ** PRINTRULES -- print rewrite rules (for debugging) 3843308Seric ** 3853308Seric ** Parameters: 3863308Seric ** none. 3873308Seric ** 3883308Seric ** Returns: 3893308Seric ** none. 3903308Seric ** 3913308Seric ** Side Effects: 3923308Seric ** prints rewrite rules. 3933308Seric */ 3943308Seric 3954319Seric # ifdef DEBUG 3964319Seric 3973308Seric printrules() 3983308Seric { 3993308Seric register struct rewrite *rwp; 4004072Seric register int ruleset; 4013308Seric 4024072Seric for (ruleset = 0; ruleset < 10; ruleset++) 4033308Seric { 4044072Seric if (RewriteRules[ruleset] == NULL) 4054072Seric continue; 4068067Seric printf("\n----Rule Set %d:", ruleset); 4073308Seric 4084072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 4093308Seric { 4108067Seric printf("\nLHS:"); 4118067Seric printav(rwp->r_lhs); 4128067Seric printf("RHS:"); 4138067Seric printav(rwp->r_rhs); 4143308Seric } 4153308Seric } 4163308Seric } 4174319Seric 4184319Seric # endif DEBUG 4194096Seric /* 4204627Seric ** MFENCODE -- crack mailer options 4214096Seric ** 4224096Seric ** These options modify the functioning of the mailer 4234096Seric ** from the configuration table. 4244096Seric ** 4254096Seric ** Parameters: 4264096Seric ** p -- pointer to vector of options. 4274096Seric ** 4284096Seric ** Returns: 4294096Seric ** option list in binary. 4304096Seric ** 4314096Seric ** Side Effects: 4324096Seric ** none. 4334096Seric */ 4344096Seric 4354096Seric struct optlist 4364096Seric { 4374096Seric char opt_name; /* external name of option */ 4386275Seric u_long opt_value; /* internal name of option */ 4394096Seric }; 4404096Seric struct optlist OptList[] = 4414096Seric { 4424096Seric 'f', M_FOPT, 4434096Seric 'r', M_ROPT, 4444096Seric 'q', M_QUIET, 4454096Seric 'S', M_RESTR, 4464096Seric 'n', M_NHDR, 4474197Seric 'l', M_LOCAL, 4484096Seric 's', M_STRIPQ, 4494096Seric 'm', M_MUSER, 4504096Seric 'F', M_NEEDFROM, 4514096Seric 'D', M_NEEDDATE, 4524096Seric 'M', M_MSGID, 4534096Seric 'u', M_USR_UPPER, 4544096Seric 'h', M_HST_UPPER, 4554096Seric 'x', M_FULLNAME, 4564096Seric 'A', M_ARPAFMT, 4575601Seric 'U', M_UGLYUUCP, 4585906Seric 'e', M_EXPENSIVE, 4596983Seric 'X', M_FULLSMTP, 4608182Seric 'C', M_CANONICAL, 4614319Seric '\0', 0 4624096Seric }; 4634096Seric 4644627Seric u_long 4654627Seric mfencode(p) 4664096Seric register char *p; 4674096Seric { 4684096Seric register struct optlist *o; 4694627Seric register u_long opts = 0; 4704096Seric 4714096Seric while (*p != '\0') 4724096Seric { 4734096Seric for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++) 4744096Seric continue; 4754096Seric if (o->opt_name == '\0') 4764096Seric syserr("bad mailer option %c", *p); 4774096Seric opts |= o->opt_value; 4784096Seric p++; 4794096Seric } 4804096Seric return (opts); 4814096Seric } 4824627Seric /* 4834627Seric ** MFDECODE -- decode mailer flags into external form. 4844627Seric ** 4854627Seric ** Parameters: 4864627Seric ** flags -- value of flags to decode. 4874627Seric ** f -- file to write them onto. 4884627Seric ** 4894627Seric ** Returns: 4904627Seric ** none. 4914627Seric ** 4924627Seric ** Side Effects: 4934627Seric ** none. 4944627Seric */ 4954627Seric 4964627Seric mfdecode(flags, f) 4974627Seric u_long flags; 4984627Seric FILE *f; 4994627Seric { 5004627Seric register struct optlist *o; 5014627Seric 5024627Seric putc('?', f); 5034627Seric for (o = OptList; o->opt_name != '\0'; o++) 5044627Seric { 5054627Seric if ((o->opt_value & flags) == o->opt_value) 5064627Seric { 5074627Seric flags &= ~o->opt_value; 5084627Seric putc(o->opt_name, f); 5094627Seric } 5104627Seric } 5114627Seric putc('?', f); 5124627Seric } 5138256Seric /* 5148256Seric ** SETOPTION -- set global processing option 5158256Seric ** 5168256Seric ** Parameters: 5178256Seric ** opt -- option name. 5188256Seric ** val -- option value (as a text string). 5198256Seric ** 5208256Seric ** Returns: 5218256Seric ** none. 5228256Seric ** 5238256Seric ** Side Effects: 5248256Seric ** Sets options as implied by the arguments. 5258256Seric */ 5268256Seric 5278256Seric setoption(opt, val) 5288256Seric char opt; 5298256Seric char *val; 5308256Seric { 5318256Seric time_t tval; 5328256Seric int ival; 533*8265Seric bool bval; 5348256Seric extern char *HelpFile; /* defined in conf.c */ 535*8265Seric extern bool atobool(); 5368256Seric 5378256Seric # ifdef DEBUG 5388256Seric if (tTd(37, 1)) 5398256Seric printf("setoption %c=%s\n", opt, val); 5408256Seric # endif DEBUG 5418256Seric 5428256Seric /* 5438256Seric ** First encode this option as appropriate. 5448256Seric */ 5458256Seric 5468256Seric if (index("rT", opt) != NULL) 5478256Seric tval = convtime(val); 5488256Seric else if (index("gLu", opt) != NULL) 5498256Seric ival = atoi(val); 550*8265Seric else if (index("s", opt) != NULL) 551*8265Seric bval = atobool(val); 5528256Seric else if (val[0] == '\0') 5538256Seric val = ""; 5548256Seric else 5558256Seric val = newstr(val); 5568256Seric 5578256Seric /* 5588256Seric ** Now do the actual assignment. 5598256Seric */ 5608256Seric 5618256Seric switch (opt) 5628256Seric { 5638256Seric case 'A': /* set default alias file */ 5648256Seric AliasFile = val; 5658256Seric break; 5668256Seric 5678256Seric case 'g': /* default gid */ 5688256Seric DefGid = ival; 5698256Seric break; 5708256Seric 5718256Seric case 'H': /* help file */ 5728256Seric HelpFile = val; 5738256Seric break; 5748256Seric 5758256Seric case 'L': /* log level */ 5768256Seric LogLevel = ival; 5778256Seric break; 5788256Seric 5798256Seric case 'Q': /* queue directory */ 5808256Seric QueueDir = val; 5818256Seric break; 5828256Seric 5838256Seric case 'r': /* read timeout */ 5848256Seric ReadTimeout = tval; 5858256Seric break; 5868256Seric 5878256Seric case 'S': /* status file */ 5888256Seric StatFile = val; 5898256Seric break; 5908256Seric 591*8265Seric case 's': /* be super safe, even if expensive */ 592*8265Seric SuperSafe = bval; 5938256Seric break; 5948256Seric 5958256Seric case 'T': /* queue timeout */ 5968256Seric TimeOut = tval; 5978256Seric break; 5988256Seric 599*8265Seric case 't': /* time zone name */ 600*8265Seric # ifdef V6 601*8265Seric StdTimezone = val; 602*8265Seric DstTimezone = index(val, ','); 603*8265Seric if (DstTimezone == NULL) 604*8265Seric goto syntax; 605*8265Seric *DstTimezone++ = '\0'; 606*8265Seric # endif V6 607*8265Seric break; 608*8265Seric 6098256Seric case 'u': /* set default uid */ 6108256Seric DefUid = ival; 6118256Seric break; 6128256Seric 6138256Seric case 'X': /* transcript file template */ 6148256Seric XcriptFile = val; 6158256Seric break; 6168256Seric 6178256Seric default: 618*8265Seric syntax: 619*8265Seric syserr("setoption: line %d: syntax error on \"%c%s\"", 620*8265Seric LineNumber, opt, val); 6218256Seric break; 6228256Seric } 6238256Seric } 624