13313Seric # include "sendmail.h" 23308Seric 3*8182Seric SCCSID(@(#)readcf.c 3.31 09/12/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. 274432Seric ** Mn p f r a Define mailer. n - internal name, 284432Seric ** p - pathname, f - flags, r - rewriting 294432Seric ** rule for sender, a - argument vector. 304432Seric ** 313308Seric ** Parameters: 323308Seric ** cfname -- control file name. 334217Seric ** safe -- set if this is a system configuration file. 344217Seric ** Non-system configuration files can not do 354217Seric ** certain things (e.g., leave the SUID bit on 364217Seric ** when executing mailers). 373308Seric ** 383308Seric ** Returns: 393308Seric ** none. 403308Seric ** 413308Seric ** Side Effects: 423308Seric ** Builds several internal tables. 433308Seric */ 443308Seric 454217Seric readcf(cfname, safe) 463308Seric char *cfname; 474217Seric bool safe; 483308Seric { 493308Seric FILE *cf; 503308Seric char buf[MAXLINE]; 513308Seric register char *p; 523308Seric struct rewrite *rwp = NULL; 533308Seric extern char **prescan(); 543308Seric extern char **copyplist(); 554061Seric int class; 564072Seric int ruleset = 0; 575909Seric char exbuf[MAXLINE]; 587231Seric char *q; 593308Seric 603308Seric cf = fopen(cfname, "r"); 613308Seric if (cf == NULL) 623308Seric { 633308Seric syserr("cannot open %s", cfname); 643308Seric exit(EX_OSFILE); 653308Seric } 663308Seric 678056Seric LineNumber = 0; 687854Seric while (fgetfolded(buf, sizeof buf, cf) != NULL) 693308Seric { 703308Seric switch (buf[0]) 713308Seric { 723308Seric case '\0': 733308Seric case '#': /* comment */ 743308Seric break; 753308Seric 763308Seric case 'R': /* rewriting rule */ 773308Seric for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 783308Seric continue; 793308Seric 803308Seric if (*p == '\0') 815909Seric { 828056Seric syserr("line %d: invalid rewrite line \"%s\"", 838056Seric LineNumber, buf); 845909Seric break; 855909Seric } 865909Seric 875909Seric /* allocate space for the rule header */ 885909Seric if (rwp == NULL) 895909Seric { 905909Seric RewriteRules[ruleset] = rwp = 915909Seric (struct rewrite *) xalloc(sizeof *rwp); 925909Seric } 933308Seric else 943308Seric { 955909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 965909Seric rwp = rwp->r_next; 975909Seric } 985909Seric rwp->r_next = NULL; 993308Seric 1005909Seric /* expand and save the LHS */ 1015909Seric *p = '\0'; 1026991Seric expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv); 1035909Seric rwp->r_lhs = prescan(exbuf, '\t'); 1045909Seric if (rwp->r_lhs != NULL) 1055909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 1065909Seric 1075909Seric /* expand and save the RHS */ 1085909Seric while (*++p == '\t') 1095909Seric continue; 1107231Seric q = p; 1117231Seric while (*p != '\0' && *p != '\t') 1127231Seric p++; 1137231Seric *p = '\0'; 1147231Seric expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv); 1155909Seric rwp->r_rhs = prescan(exbuf, '\t'); 1165909Seric if (rwp->r_rhs != NULL) 1175909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 1183308Seric break; 1193308Seric 1204072Seric case 'S': /* select rewriting set */ 1214072Seric ruleset = atoi(&buf[1]); 1228056Seric if (ruleset >= MAXRWSETS || ruleset < 0) 1238056Seric { 1248056Seric syserr("readcf: line %d: bad ruleset %d (%d max)", 1258056Seric LineNumber, ruleset, MAXRWSETS); 1268056Seric ruleset = 0; 1278056Seric } 1284072Seric rwp = NULL; 1294072Seric break; 1304072Seric 1313308Seric case 'D': /* macro definition */ 1323308Seric define(buf[1], newstr(&buf[2])); 1333308Seric break; 1343308Seric 1353387Seric case 'H': /* required header line */ 1364088Seric (void) chompheader(&buf[1], TRUE); 1373387Seric break; 1383387Seric 1394061Seric case 'C': /* word class */ 1404432Seric case 'F': /* word class from file */ 1414061Seric class = buf[1]; 1424061Seric if (!isalpha(class)) 1434061Seric goto badline; 1444061Seric if (isupper(class)) 1454061Seric class -= 'A'; 1464061Seric else 1474061Seric class -= 'a'; 1484432Seric 1494432Seric /* read list of words from argument or file */ 1504432Seric if (buf[0] == 'F') 1514432Seric { 1524432Seric /* read from file */ 1534432Seric for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 1544432Seric continue; 1554432Seric if (*p == '\0') 1564432Seric p = "%s"; 1574432Seric else 1584432Seric { 1594432Seric *p = '\0'; 1604432Seric while (isspace(*++p)) 1614432Seric continue; 1624432Seric } 1634432Seric fileclass(class, &buf[2], p); 1644432Seric break; 1654432Seric } 1664061Seric 1674432Seric /* scan the list of words and set class for all */ 1684061Seric for (p = &buf[2]; *p != '\0'; ) 1694061Seric { 1704061Seric register char *wd; 1714061Seric char delim; 1724061Seric register STAB *s; 1734061Seric 1744061Seric while (*p != '\0' && isspace(*p)) 1754061Seric p++; 1764061Seric wd = p; 1774061Seric while (*p != '\0' && !isspace(*p)) 1784061Seric p++; 1794061Seric delim = *p; 1804061Seric *p = '\0'; 1814061Seric if (wd[0] != '\0') 1824061Seric { 1834103Seric s = stab(wd, ST_CLASS, ST_ENTER); 1846275Seric s->s_class |= 1L << class; 1854061Seric } 1864061Seric *p = delim; 1874061Seric } 1884061Seric break; 1894061Seric 1904096Seric case 'M': /* define mailer */ 1914217Seric makemailer(&buf[1], safe); 1924096Seric break; 1934096Seric 1943308Seric default: 1954061Seric badline: 1968056Seric syserr("readcf: line %d: unknown control line \"%s\"", 1978056Seric LineNumber, buf); 1983308Seric } 1993308Seric } 2004096Seric } 2014096Seric /* 2024432Seric ** FILECLASS -- read members of a class from a file 2034432Seric ** 2044432Seric ** Parameters: 2054432Seric ** class -- class to define. 2064432Seric ** filename -- name of file to read. 2074432Seric ** fmt -- scanf string to use for match. 2084432Seric ** 2094432Seric ** Returns: 2104432Seric ** none 2114432Seric ** 2124432Seric ** Side Effects: 2134432Seric ** 2144432Seric ** puts all lines in filename that match a scanf into 2154432Seric ** the named class. 2164432Seric */ 2174432Seric 2184432Seric fileclass(class, filename, fmt) 2194432Seric int class; 2204432Seric char *filename; 2214432Seric char *fmt; 2224432Seric { 2234432Seric register FILE *f; 2244432Seric char buf[MAXLINE]; 2254432Seric 2264432Seric f = fopen(filename, "r"); 2274432Seric if (f == NULL) 2284432Seric { 2294432Seric syserr("cannot open %s", filename); 2304432Seric return; 2314432Seric } 2324432Seric 2334432Seric while (fgets(buf, sizeof buf, f) != NULL) 2344432Seric { 2354432Seric register STAB *s; 2364432Seric char wordbuf[MAXNAME+1]; 2374432Seric 2384432Seric if (sscanf(buf, fmt, wordbuf) != 1) 2394432Seric continue; 2404432Seric s = stab(wordbuf, ST_CLASS, ST_ENTER); 2416275Seric s->s_class |= 1L << class; 2424432Seric } 2434432Seric 2444627Seric (void) fclose(f); 2454432Seric } 2464432Seric /* 2474096Seric ** MAKEMAILER -- define a new mailer. 2484096Seric ** 2494096Seric ** Parameters: 2504096Seric ** line -- description of mailer. This is in tokens 2514096Seric ** separated by white space. The fields are: 2524096Seric ** * the name of the mailer, as refered to 2534096Seric ** in the rewriting rules. 2544096Seric ** * the pathname of the program to fork to 2554096Seric ** execute it. 2564096Seric ** * the options needed by this program. 2574096Seric ** * the macro string needed to translate 2584096Seric ** a local "from" name to one that can be 2594096Seric ** returned to this machine. 2604096Seric ** * the argument vector (a series of parameters). 2614217Seric ** safe -- set if this is a safe configuration file. 2624096Seric ** 2634096Seric ** Returns: 2644096Seric ** none. 2654096Seric ** 2664096Seric ** Side Effects: 2674096Seric ** enters the mailer into the mailer table. 2684096Seric */ 2693308Seric 2704096Seric # define SETWORD \ 2714096Seric { \ 2724096Seric while (*p != '\0' && isspace(*p)) \ 2734096Seric p++; \ 2744096Seric q = p; \ 2754096Seric while (*p != '\0' && !isspace(*p)) \ 2764096Seric p++; \ 2774096Seric if (*p != '\0') \ 2784096Seric *p++ = '\0'; \ 2794096Seric } 2804096Seric 2814217Seric makemailer(line, safe) 2824096Seric char *line; 2834217Seric bool safe; 2844096Seric { 2854096Seric register char *p; 2864096Seric register char *q; 2878067Seric register struct mailer *m; 2888067Seric register STAB *s; 2898067Seric int i; 2904096Seric char *mname; 2914096Seric char *mpath; 2924627Seric u_long mopts; 2938067Seric short mrset, msset; 2948067Seric char *margv[MAXPV + 1]; 2954627Seric extern u_long mfencode(); 2964096Seric extern int NextMailer; 2974096Seric 2984096Seric if (NextMailer >= MAXMAILERS) 2994096Seric { 3008056Seric syserr("readcf: line %d: too many mailers defined (%d max)", 3018056Seric LineNumber, MAXMAILERS); 3024096Seric return; 3034096Seric } 3044096Seric 3054096Seric /* collect initial information */ 3064096Seric p = line; 3074096Seric SETWORD; 3084096Seric mname = q; 3094096Seric SETWORD; 3104096Seric mpath = q; 3114096Seric SETWORD; 3124627Seric mopts = mfencode(q); 3134217Seric if (!safe) 3144217Seric mopts &= ~M_RESTR; 3154096Seric SETWORD; 3168067Seric msset = atoi(q); 3178067Seric SETWORD; 3188067Seric mrset = atoi(q); 3194096Seric 3204096Seric if (*p == '\0') 3214096Seric { 3228056Seric syserr("readcf: line %d: invalid M line in configuration file", 3238056Seric LineNumber); 3244096Seric return; 3254096Seric } 3268067Seric if (msset >= MAXRWSETS || mrset >= MAXRWSETS) 3278067Seric { 3288067Seric syserr("readcf: line %d: invalid rewrite set, %d max", 3298067Seric LineNumber, MAXRWSETS); 3308067Seric return; 3318067Seric } 3324096Seric 3334096Seric /* allocate a mailer */ 3344096Seric m = (struct mailer *) xalloc(sizeof *m); 3354096Seric m->m_name = newstr(mname); 3364096Seric m->m_mailer = newstr(mpath); 3374096Seric m->m_flags = mopts; 3388067Seric m->m_r_rwset = mrset; 3398067Seric m->m_s_rwset = msset; 3404096Seric m->m_badstat = EX_UNAVAILABLE; 3414439Seric m->m_mno = NextMailer; 3424096Seric Mailer[NextMailer++] = m; 3434096Seric 3444096Seric /* collect the argument vector */ 3454096Seric for (i = 0; i < MAXPV - 1 && *p != '\0'; i++) 3464096Seric { 3474096Seric SETWORD; 3484096Seric margv[i] = newstr(q); 3494096Seric } 3504096Seric margv[i++] = NULL; 3514096Seric 3524096Seric /* save the argv */ 3537009Seric m->m_argv = (char **) xalloc(sizeof margv[0] * i); 3544096Seric bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i); 3554439Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 3564439Seric s->s_mailer = m; 3573308Seric } 3583308Seric /* 3593308Seric ** PRINTRULES -- print rewrite rules (for debugging) 3603308Seric ** 3613308Seric ** Parameters: 3623308Seric ** none. 3633308Seric ** 3643308Seric ** Returns: 3653308Seric ** none. 3663308Seric ** 3673308Seric ** Side Effects: 3683308Seric ** prints rewrite rules. 3693308Seric */ 3703308Seric 3714319Seric # ifdef DEBUG 3724319Seric 3733308Seric printrules() 3743308Seric { 3753308Seric register struct rewrite *rwp; 3764072Seric register int ruleset; 3773308Seric 3784072Seric for (ruleset = 0; ruleset < 10; ruleset++) 3793308Seric { 3804072Seric if (RewriteRules[ruleset] == NULL) 3814072Seric continue; 3828067Seric printf("\n----Rule Set %d:", ruleset); 3833308Seric 3844072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 3853308Seric { 3868067Seric printf("\nLHS:"); 3878067Seric printav(rwp->r_lhs); 3888067Seric printf("RHS:"); 3898067Seric printav(rwp->r_rhs); 3903308Seric } 3913308Seric } 3923308Seric } 3934319Seric 3944319Seric # endif DEBUG 3954096Seric /* 3964627Seric ** MFENCODE -- crack mailer options 3974096Seric ** 3984096Seric ** These options modify the functioning of the mailer 3994096Seric ** from the configuration table. 4004096Seric ** 4014096Seric ** Parameters: 4024096Seric ** p -- pointer to vector of options. 4034096Seric ** 4044096Seric ** Returns: 4054096Seric ** option list in binary. 4064096Seric ** 4074096Seric ** Side Effects: 4084096Seric ** none. 4094096Seric */ 4104096Seric 4114096Seric struct optlist 4124096Seric { 4134096Seric char opt_name; /* external name of option */ 4146275Seric u_long opt_value; /* internal name of option */ 4154096Seric }; 4164096Seric struct optlist OptList[] = 4174096Seric { 4184096Seric 'f', M_FOPT, 4194096Seric 'r', M_ROPT, 4204096Seric 'q', M_QUIET, 4214096Seric 'S', M_RESTR, 4224096Seric 'n', M_NHDR, 4234197Seric 'l', M_LOCAL, 4244096Seric 's', M_STRIPQ, 4254096Seric 'm', M_MUSER, 4264096Seric 'F', M_NEEDFROM, 4274096Seric 'D', M_NEEDDATE, 4284096Seric 'M', M_MSGID, 4294096Seric 'u', M_USR_UPPER, 4304096Seric 'h', M_HST_UPPER, 4314096Seric 'x', M_FULLNAME, 4324096Seric 'A', M_ARPAFMT, 4335601Seric 'U', M_UGLYUUCP, 4345906Seric 'e', M_EXPENSIVE, 4356983Seric 'X', M_FULLSMTP, 436*8182Seric 'C', M_CANONICAL, 4374319Seric '\0', 0 4384096Seric }; 4394096Seric 4404627Seric u_long 4414627Seric mfencode(p) 4424096Seric register char *p; 4434096Seric { 4444096Seric register struct optlist *o; 4454627Seric register u_long opts = 0; 4464096Seric 4474096Seric while (*p != '\0') 4484096Seric { 4494096Seric for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++) 4504096Seric continue; 4514096Seric if (o->opt_name == '\0') 4524096Seric syserr("bad mailer option %c", *p); 4534096Seric opts |= o->opt_value; 4544096Seric p++; 4554096Seric } 4564096Seric return (opts); 4574096Seric } 4584627Seric /* 4594627Seric ** MFDECODE -- decode mailer flags into external form. 4604627Seric ** 4614627Seric ** Parameters: 4624627Seric ** flags -- value of flags to decode. 4634627Seric ** f -- file to write them onto. 4644627Seric ** 4654627Seric ** Returns: 4664627Seric ** none. 4674627Seric ** 4684627Seric ** Side Effects: 4694627Seric ** none. 4704627Seric */ 4714627Seric 4724627Seric mfdecode(flags, f) 4734627Seric u_long flags; 4744627Seric FILE *f; 4754627Seric { 4764627Seric register struct optlist *o; 4774627Seric 4784627Seric putc('?', f); 4794627Seric for (o = OptList; o->opt_name != '\0'; o++) 4804627Seric { 4814627Seric if ((o->opt_value & flags) == o->opt_value) 4824627Seric { 4834627Seric flags &= ~o->opt_value; 4844627Seric putc(o->opt_name, f); 4854627Seric } 4864627Seric } 4874627Seric putc('?', f); 4884627Seric } 489