13313Seric # include "sendmail.h" 23308Seric 3*8252Seric SCCSID(@(#)readcf.c 3.32 09/24/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. 27*8252Seric ** Mn p f s r a Define mailer. n - internal name, 28*8252Seric ** p - pathname, f - flags, s - rewriting 29*8252Seric ** ruleset for sender, s - rewriting ruleset 30*8252Seric ** for recipients, a - argument vector. 31*8252Seric ** Oxvalue Set option x to value. 32*8252Seric ** 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 197*8252Seric case 'O': /* set option */ 198*8252Seric if (buf[2] == '\0') 199*8252Seric Option[buf[1]] = ""; 200*8252Seric else 201*8252Seric Option[buf[1]] = newstr(&buf[2]); 202*8252Seric break; 203*8252Seric 204*8252Seric case 'P': /* set precedence */ 205*8252Seric if (NumPriorities >= MAXPRIORITIES) 206*8252Seric { 207*8252Seric syserr("readcf: line %d: too many P lines, %d max", 208*8252Seric LineNumber, MAXPRIORITIES); 209*8252Seric break; 210*8252Seric } 211*8252Seric for (p = &buf[1]; *p != '\0' && *p != '='; p++) 212*8252Seric continue; 213*8252Seric if (*p == '\0') 214*8252Seric goto badline; 215*8252Seric *p = '\0'; 216*8252Seric Priorities[NumPriorities].pri_name = newstr(&buf[1]); 217*8252Seric Priorities[NumPriorities].pri_val = atoi(++p); 218*8252Seric NumPriorities++; 219*8252Seric break; 220*8252Seric 2213308Seric default: 2224061Seric badline: 2238056Seric syserr("readcf: line %d: unknown control line \"%s\"", 2248056Seric LineNumber, buf); 2253308Seric } 2263308Seric } 2274096Seric } 2284096Seric /* 2294432Seric ** FILECLASS -- read members of a class from a file 2304432Seric ** 2314432Seric ** Parameters: 2324432Seric ** class -- class to define. 2334432Seric ** filename -- name of file to read. 2344432Seric ** fmt -- scanf string to use for match. 2354432Seric ** 2364432Seric ** Returns: 2374432Seric ** none 2384432Seric ** 2394432Seric ** Side Effects: 2404432Seric ** 2414432Seric ** puts all lines in filename that match a scanf into 2424432Seric ** the named class. 2434432Seric */ 2444432Seric 2454432Seric fileclass(class, filename, fmt) 2464432Seric int class; 2474432Seric char *filename; 2484432Seric char *fmt; 2494432Seric { 2504432Seric register FILE *f; 2514432Seric char buf[MAXLINE]; 2524432Seric 2534432Seric f = fopen(filename, "r"); 2544432Seric if (f == NULL) 2554432Seric { 2564432Seric syserr("cannot open %s", filename); 2574432Seric return; 2584432Seric } 2594432Seric 2604432Seric while (fgets(buf, sizeof buf, f) != NULL) 2614432Seric { 2624432Seric register STAB *s; 2634432Seric char wordbuf[MAXNAME+1]; 2644432Seric 2654432Seric if (sscanf(buf, fmt, wordbuf) != 1) 2664432Seric continue; 2674432Seric s = stab(wordbuf, ST_CLASS, ST_ENTER); 2686275Seric s->s_class |= 1L << class; 2694432Seric } 2704432Seric 2714627Seric (void) fclose(f); 2724432Seric } 2734432Seric /* 2744096Seric ** MAKEMAILER -- define a new mailer. 2754096Seric ** 2764096Seric ** Parameters: 2774096Seric ** line -- description of mailer. This is in tokens 2784096Seric ** separated by white space. The fields are: 2794096Seric ** * the name of the mailer, as refered to 2804096Seric ** in the rewriting rules. 2814096Seric ** * the pathname of the program to fork to 2824096Seric ** execute it. 2834096Seric ** * the options needed by this program. 2844096Seric ** * the macro string needed to translate 2854096Seric ** a local "from" name to one that can be 2864096Seric ** returned to this machine. 2874096Seric ** * the argument vector (a series of parameters). 2884217Seric ** safe -- set if this is a safe configuration file. 2894096Seric ** 2904096Seric ** Returns: 2914096Seric ** none. 2924096Seric ** 2934096Seric ** Side Effects: 2944096Seric ** enters the mailer into the mailer table. 2954096Seric */ 2963308Seric 2974096Seric # define SETWORD \ 2984096Seric { \ 2994096Seric while (*p != '\0' && isspace(*p)) \ 3004096Seric p++; \ 3014096Seric q = p; \ 3024096Seric while (*p != '\0' && !isspace(*p)) \ 3034096Seric p++; \ 3044096Seric if (*p != '\0') \ 3054096Seric *p++ = '\0'; \ 3064096Seric } 3074096Seric 3084217Seric makemailer(line, safe) 3094096Seric char *line; 3104217Seric bool safe; 3114096Seric { 3124096Seric register char *p; 3134096Seric register char *q; 3148067Seric register struct mailer *m; 3158067Seric register STAB *s; 3168067Seric int i; 3174096Seric char *mname; 3184096Seric char *mpath; 3194627Seric u_long mopts; 3208067Seric short mrset, msset; 3218067Seric char *margv[MAXPV + 1]; 3224627Seric extern u_long mfencode(); 3234096Seric extern int NextMailer; 3244096Seric 3254096Seric if (NextMailer >= MAXMAILERS) 3264096Seric { 3278056Seric syserr("readcf: line %d: too many mailers defined (%d max)", 3288056Seric LineNumber, MAXMAILERS); 3294096Seric return; 3304096Seric } 3314096Seric 3324096Seric /* collect initial information */ 3334096Seric p = line; 3344096Seric SETWORD; 3354096Seric mname = q; 3364096Seric SETWORD; 3374096Seric mpath = q; 3384096Seric SETWORD; 3394627Seric mopts = mfencode(q); 3404217Seric if (!safe) 3414217Seric mopts &= ~M_RESTR; 3424096Seric SETWORD; 3438067Seric msset = atoi(q); 3448067Seric SETWORD; 3458067Seric mrset = atoi(q); 3464096Seric 3474096Seric if (*p == '\0') 3484096Seric { 3498056Seric syserr("readcf: line %d: invalid M line in configuration file", 3508056Seric LineNumber); 3514096Seric return; 3524096Seric } 3538067Seric if (msset >= MAXRWSETS || mrset >= MAXRWSETS) 3548067Seric { 3558067Seric syserr("readcf: line %d: invalid rewrite set, %d max", 3568067Seric LineNumber, MAXRWSETS); 3578067Seric return; 3588067Seric } 3594096Seric 3604096Seric /* allocate a mailer */ 3614096Seric m = (struct mailer *) xalloc(sizeof *m); 3624096Seric m->m_name = newstr(mname); 3634096Seric m->m_mailer = newstr(mpath); 3644096Seric m->m_flags = mopts; 3658067Seric m->m_r_rwset = mrset; 3668067Seric m->m_s_rwset = msset; 3674096Seric m->m_badstat = EX_UNAVAILABLE; 3684439Seric m->m_mno = NextMailer; 3694096Seric Mailer[NextMailer++] = m; 3704096Seric 3714096Seric /* collect the argument vector */ 3724096Seric for (i = 0; i < MAXPV - 1 && *p != '\0'; i++) 3734096Seric { 3744096Seric SETWORD; 3754096Seric margv[i] = newstr(q); 3764096Seric } 3774096Seric margv[i++] = NULL; 3784096Seric 3794096Seric /* save the argv */ 3807009Seric m->m_argv = (char **) xalloc(sizeof margv[0] * i); 3814096Seric bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i); 3824439Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 3834439Seric s->s_mailer = m; 3843308Seric } 3853308Seric /* 3863308Seric ** PRINTRULES -- print rewrite rules (for debugging) 3873308Seric ** 3883308Seric ** Parameters: 3893308Seric ** none. 3903308Seric ** 3913308Seric ** Returns: 3923308Seric ** none. 3933308Seric ** 3943308Seric ** Side Effects: 3953308Seric ** prints rewrite rules. 3963308Seric */ 3973308Seric 3984319Seric # ifdef DEBUG 3994319Seric 4003308Seric printrules() 4013308Seric { 4023308Seric register struct rewrite *rwp; 4034072Seric register int ruleset; 4043308Seric 4054072Seric for (ruleset = 0; ruleset < 10; ruleset++) 4063308Seric { 4074072Seric if (RewriteRules[ruleset] == NULL) 4084072Seric continue; 4098067Seric printf("\n----Rule Set %d:", ruleset); 4103308Seric 4114072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 4123308Seric { 4138067Seric printf("\nLHS:"); 4148067Seric printav(rwp->r_lhs); 4158067Seric printf("RHS:"); 4168067Seric printav(rwp->r_rhs); 4173308Seric } 4183308Seric } 4193308Seric } 4204319Seric 4214319Seric # endif DEBUG 4224096Seric /* 4234627Seric ** MFENCODE -- crack mailer options 4244096Seric ** 4254096Seric ** These options modify the functioning of the mailer 4264096Seric ** from the configuration table. 4274096Seric ** 4284096Seric ** Parameters: 4294096Seric ** p -- pointer to vector of options. 4304096Seric ** 4314096Seric ** Returns: 4324096Seric ** option list in binary. 4334096Seric ** 4344096Seric ** Side Effects: 4354096Seric ** none. 4364096Seric */ 4374096Seric 4384096Seric struct optlist 4394096Seric { 4404096Seric char opt_name; /* external name of option */ 4416275Seric u_long opt_value; /* internal name of option */ 4424096Seric }; 4434096Seric struct optlist OptList[] = 4444096Seric { 4454096Seric 'f', M_FOPT, 4464096Seric 'r', M_ROPT, 4474096Seric 'q', M_QUIET, 4484096Seric 'S', M_RESTR, 4494096Seric 'n', M_NHDR, 4504197Seric 'l', M_LOCAL, 4514096Seric 's', M_STRIPQ, 4524096Seric 'm', M_MUSER, 4534096Seric 'F', M_NEEDFROM, 4544096Seric 'D', M_NEEDDATE, 4554096Seric 'M', M_MSGID, 4564096Seric 'u', M_USR_UPPER, 4574096Seric 'h', M_HST_UPPER, 4584096Seric 'x', M_FULLNAME, 4594096Seric 'A', M_ARPAFMT, 4605601Seric 'U', M_UGLYUUCP, 4615906Seric 'e', M_EXPENSIVE, 4626983Seric 'X', M_FULLSMTP, 4638182Seric 'C', M_CANONICAL, 4644319Seric '\0', 0 4654096Seric }; 4664096Seric 4674627Seric u_long 4684627Seric mfencode(p) 4694096Seric register char *p; 4704096Seric { 4714096Seric register struct optlist *o; 4724627Seric register u_long opts = 0; 4734096Seric 4744096Seric while (*p != '\0') 4754096Seric { 4764096Seric for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++) 4774096Seric continue; 4784096Seric if (o->opt_name == '\0') 4794096Seric syserr("bad mailer option %c", *p); 4804096Seric opts |= o->opt_value; 4814096Seric p++; 4824096Seric } 4834096Seric return (opts); 4844096Seric } 4854627Seric /* 4864627Seric ** MFDECODE -- decode mailer flags into external form. 4874627Seric ** 4884627Seric ** Parameters: 4894627Seric ** flags -- value of flags to decode. 4904627Seric ** f -- file to write them onto. 4914627Seric ** 4924627Seric ** Returns: 4934627Seric ** none. 4944627Seric ** 4954627Seric ** Side Effects: 4964627Seric ** none. 4974627Seric */ 4984627Seric 4994627Seric mfdecode(flags, f) 5004627Seric u_long flags; 5014627Seric FILE *f; 5024627Seric { 5034627Seric register struct optlist *o; 5044627Seric 5054627Seric putc('?', f); 5064627Seric for (o = OptList; o->opt_name != '\0'; o++) 5074627Seric { 5084627Seric if ((o->opt_value & flags) == o->opt_value) 5094627Seric { 5104627Seric flags &= ~o->opt_value; 5114627Seric putc(o->opt_name, f); 5124627Seric } 5134627Seric } 5144627Seric putc('?', f); 5154627Seric } 516