13313Seric # include "sendmail.h" 23308Seric 3*5909Seric SCCSID(@(#)readcf.c 3.21 02/20/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 454072Seric struct rewrite *RewriteRules[10]; 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; 60*5909Seric char exbuf[MAXLINE]; 613308Seric 623308Seric cf = fopen(cfname, "r"); 633308Seric if (cf == NULL) 643308Seric { 653308Seric syserr("cannot open %s", cfname); 663308Seric exit(EX_OSFILE); 673308Seric } 683308Seric 693308Seric while (fgets(buf, sizeof buf, cf) != NULL) 703308Seric { 713308Seric p = rindex(buf, '\n'); 723308Seric if (p != NULL) 733308Seric *p = '\0'; 743308Seric 753308Seric switch (buf[0]) 763308Seric { 773308Seric case '\n': 783308Seric case '\0': 793308Seric case ' ': 803308Seric case '\t': 813308Seric case '#': /* comment */ 823308Seric break; 833308Seric 843308Seric case 'R': /* rewriting rule */ 853308Seric for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 863308Seric continue; 873308Seric 883308Seric if (*p == '\0') 89*5909Seric { 903308Seric syserr("invalid rewrite line \"%s\"", buf); 91*5909Seric break; 92*5909Seric } 93*5909Seric 94*5909Seric /* allocate space for the rule header */ 95*5909Seric if (rwp == NULL) 96*5909Seric { 97*5909Seric RewriteRules[ruleset] = rwp = 98*5909Seric (struct rewrite *) xalloc(sizeof *rwp); 99*5909Seric } 1003308Seric else 1013308Seric { 102*5909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 103*5909Seric rwp = rwp->r_next; 104*5909Seric } 105*5909Seric rwp->r_next = NULL; 1063308Seric 107*5909Seric /* expand and save the LHS */ 108*5909Seric *p = '\0'; 109*5909Seric (void) expand(&buf[1], exbuf, &exbuf[sizeof exbuf]); 110*5909Seric rwp->r_lhs = prescan(exbuf, '\t'); 111*5909Seric if (rwp->r_lhs != NULL) 112*5909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 113*5909Seric 114*5909Seric /* expand and save the RHS */ 115*5909Seric while (*++p == '\t') 116*5909Seric continue; 117*5909Seric (void) expand(p, exbuf, &exbuf[sizeof exbuf]); 118*5909Seric rwp->r_rhs = prescan(exbuf, '\t'); 119*5909Seric if (rwp->r_rhs != NULL) 120*5909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 1213308Seric break; 1223308Seric 1234072Seric case 'S': /* select rewriting set */ 1244072Seric ruleset = atoi(&buf[1]); 1254072Seric rwp = NULL; 1264072Seric break; 1274072Seric 1283308Seric case 'D': /* macro definition */ 1293308Seric define(buf[1], newstr(&buf[2])); 1303308Seric break; 1313308Seric 1323387Seric case 'H': /* required header line */ 1334088Seric (void) chompheader(&buf[1], TRUE); 1343387Seric break; 1353387Seric 1364061Seric case 'C': /* word class */ 1374432Seric case 'F': /* word class from file */ 1384061Seric class = buf[1]; 1394061Seric if (!isalpha(class)) 1404061Seric goto badline; 1414061Seric if (isupper(class)) 1424061Seric class -= 'A'; 1434061Seric else 1444061Seric class -= 'a'; 1454432Seric 1464432Seric /* read list of words from argument or file */ 1474432Seric if (buf[0] == 'F') 1484432Seric { 1494432Seric /* read from file */ 1504432Seric for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 1514432Seric continue; 1524432Seric if (*p == '\0') 1534432Seric p = "%s"; 1544432Seric else 1554432Seric { 1564432Seric *p = '\0'; 1574432Seric while (isspace(*++p)) 1584432Seric continue; 1594432Seric } 1604432Seric fileclass(class, &buf[2], p); 1614432Seric break; 1624432Seric } 1634061Seric 1644432Seric /* scan the list of words and set class for all */ 1654061Seric for (p = &buf[2]; *p != '\0'; ) 1664061Seric { 1674061Seric register char *wd; 1684061Seric char delim; 1694061Seric register STAB *s; 1704061Seric 1714061Seric while (*p != '\0' && isspace(*p)) 1724061Seric p++; 1734061Seric wd = p; 1744061Seric while (*p != '\0' && !isspace(*p)) 1754061Seric p++; 1764061Seric delim = *p; 1774061Seric *p = '\0'; 1784061Seric if (wd[0] != '\0') 1794061Seric { 1804103Seric s = stab(wd, ST_CLASS, ST_ENTER); 1814061Seric s->s_class |= 1 << class; 1824061Seric } 1834061Seric *p = delim; 1844061Seric } 1854061Seric break; 1864061Seric 1874096Seric case 'M': /* define mailer */ 1884217Seric makemailer(&buf[1], safe); 1894096Seric break; 1904096Seric 1913308Seric default: 1924061Seric badline: 1933308Seric syserr("unknown control line \"%s\"", buf); 1943308Seric } 1953308Seric } 1964096Seric } 1974096Seric /* 1984432Seric ** FILECLASS -- read members of a class from a file 1994432Seric ** 2004432Seric ** Parameters: 2014432Seric ** class -- class to define. 2024432Seric ** filename -- name of file to read. 2034432Seric ** fmt -- scanf string to use for match. 2044432Seric ** 2054432Seric ** Returns: 2064432Seric ** none 2074432Seric ** 2084432Seric ** Side Effects: 2094432Seric ** 2104432Seric ** puts all lines in filename that match a scanf into 2114432Seric ** the named class. 2124432Seric */ 2134432Seric 2144432Seric fileclass(class, filename, fmt) 2154432Seric int class; 2164432Seric char *filename; 2174432Seric char *fmt; 2184432Seric { 2194432Seric register FILE *f; 2204432Seric char buf[MAXLINE]; 2214432Seric 2224432Seric f = fopen(filename, "r"); 2234432Seric if (f == NULL) 2244432Seric { 2254432Seric syserr("cannot open %s", filename); 2264432Seric return; 2274432Seric } 2284432Seric 2294432Seric while (fgets(buf, sizeof buf, f) != NULL) 2304432Seric { 2314432Seric register STAB *s; 2324432Seric char wordbuf[MAXNAME+1]; 2334432Seric 2344432Seric if (sscanf(buf, fmt, wordbuf) != 1) 2354432Seric continue; 2364432Seric s = stab(wordbuf, ST_CLASS, ST_ENTER); 2374432Seric s->s_class |= 1 << class; 2384432Seric } 2394432Seric 2404627Seric (void) fclose(f); 2414432Seric } 2424432Seric /* 2434096Seric ** MAKEMAILER -- define a new mailer. 2444096Seric ** 2454096Seric ** Parameters: 2464096Seric ** line -- description of mailer. This is in tokens 2474096Seric ** separated by white space. The fields are: 2484096Seric ** * the name of the mailer, as refered to 2494096Seric ** in the rewriting rules. 2504096Seric ** * the pathname of the program to fork to 2514096Seric ** execute it. 2524096Seric ** * the options needed by this program. 2534096Seric ** * the macro string needed to translate 2544096Seric ** a local "from" name to one that can be 2554096Seric ** returned to this machine. 2564096Seric ** * the argument vector (a series of parameters). 2574217Seric ** safe -- set if this is a safe configuration file. 2584096Seric ** 2594096Seric ** Returns: 2604096Seric ** none. 2614096Seric ** 2624096Seric ** Side Effects: 2634096Seric ** enters the mailer into the mailer table. 2644096Seric */ 2653308Seric 2664096Seric # define SETWORD \ 2674096Seric { \ 2684096Seric while (*p != '\0' && isspace(*p)) \ 2694096Seric p++; \ 2704096Seric q = p; \ 2714096Seric while (*p != '\0' && !isspace(*p)) \ 2724096Seric p++; \ 2734096Seric if (*p != '\0') \ 2744096Seric *p++ = '\0'; \ 2754096Seric } 2764096Seric 2774217Seric makemailer(line, safe) 2784096Seric char *line; 2794217Seric bool safe; 2804096Seric { 2814096Seric register char *p; 2824096Seric register char *q; 2834096Seric char *mname; 2844096Seric char *mpath; 2854627Seric u_long mopts; 2864627Seric extern u_long mfencode(); 2874096Seric char *mfrom; 2884096Seric register struct mailer *m; 2894096Seric char *margv[MAXPV + 1]; 2904096Seric register int i; 2914096Seric extern int NextMailer; 2924439Seric STAB *s; 2934096Seric 2944096Seric if (NextMailer >= MAXMAILERS) 2954096Seric { 2964096Seric syserr("Too many mailers defined"); 2974096Seric return; 2984096Seric } 2994096Seric 3004096Seric /* collect initial information */ 3014096Seric p = line; 3024096Seric SETWORD; 3034096Seric mname = q; 3044096Seric SETWORD; 3054096Seric mpath = q; 3064096Seric SETWORD; 3074627Seric mopts = mfencode(q); 3084217Seric if (!safe) 3094217Seric mopts &= ~M_RESTR; 3104096Seric SETWORD; 3114096Seric mfrom = q; 3124096Seric 3134096Seric if (*p == '\0') 3144096Seric { 3154096Seric syserr("invalid M line in configuration file"); 3164096Seric return; 3174096Seric } 3184096Seric 3194096Seric /* allocate a mailer */ 3204096Seric m = (struct mailer *) xalloc(sizeof *m); 3214096Seric m->m_name = newstr(mname); 3224096Seric m->m_mailer = newstr(mpath); 3234096Seric m->m_flags = mopts; 3244096Seric m->m_from = newstr(mfrom); 3254096Seric m->m_badstat = EX_UNAVAILABLE; 3264439Seric m->m_mno = NextMailer; 3274096Seric Mailer[NextMailer++] = m; 3284096Seric 3294096Seric /* collect the argument vector */ 3304096Seric for (i = 0; i < MAXPV - 1 && *p != '\0'; i++) 3314096Seric { 3324096Seric SETWORD; 3334096Seric margv[i] = newstr(q); 3344096Seric } 3354096Seric margv[i++] = NULL; 3364096Seric 3374096Seric /* save the argv */ 3384319Seric m->m_argv = (char **) xalloc((unsigned) (sizeof margv[0] * i)); 3394096Seric bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i); 3404439Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 3414439Seric s->s_mailer = m; 3423308Seric } 3433308Seric /* 3443308Seric ** PRINTRULES -- print rewrite rules (for debugging) 3453308Seric ** 3463308Seric ** Parameters: 3473308Seric ** none. 3483308Seric ** 3493308Seric ** Returns: 3503308Seric ** none. 3513308Seric ** 3523308Seric ** Side Effects: 3533308Seric ** prints rewrite rules. 3543308Seric */ 3553308Seric 3564319Seric # ifdef DEBUG 3574319Seric 3583308Seric printrules() 3593308Seric { 3603308Seric register struct rewrite *rwp; 3614072Seric register int ruleset; 3623308Seric 3634072Seric for (ruleset = 0; ruleset < 10; ruleset++) 3643308Seric { 3654072Seric if (RewriteRules[ruleset] == NULL) 3664072Seric continue; 3674072Seric printf("\n----Rule Set %d:\n", ruleset); 3683308Seric 3694072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 3703308Seric { 3714072Seric register char **av; 3724072Seric 3734072Seric printf("\n"); 3744072Seric for (av = rwp->r_lhs; *av != NULL; av++) 3754072Seric { 3764072Seric xputs(*av); 3774072Seric putchar('_'); 3784072Seric } 3794072Seric printf("\n\t"); 3804072Seric for (av = rwp->r_rhs; *av != NULL; av++) 3814072Seric { 3824072Seric xputs(*av); 3834072Seric putchar('_'); 3844072Seric } 3854072Seric printf("\n"); 3863308Seric } 3873308Seric } 3883308Seric } 3894319Seric 3904319Seric # endif DEBUG 3914096Seric /* 3924627Seric ** MFENCODE -- crack mailer options 3934096Seric ** 3944096Seric ** These options modify the functioning of the mailer 3954096Seric ** from the configuration table. 3964096Seric ** 3974096Seric ** Parameters: 3984096Seric ** p -- pointer to vector of options. 3994096Seric ** 4004096Seric ** Returns: 4014096Seric ** option list in binary. 4024096Seric ** 4034096Seric ** Side Effects: 4044096Seric ** none. 4054096Seric */ 4064096Seric 4074096Seric struct optlist 4084096Seric { 4094096Seric char opt_name; /* external name of option */ 4104096Seric int opt_value; /* internal name of option */ 4114096Seric }; 4124096Seric struct optlist OptList[] = 4134096Seric { 4144096Seric 'f', M_FOPT, 4154096Seric 'r', M_ROPT, 4164096Seric 'q', M_QUIET, 4174096Seric 'S', M_RESTR, 4184096Seric 'n', M_NHDR, 4194197Seric 'l', M_LOCAL, 4204096Seric 's', M_STRIPQ, 4214096Seric 'm', M_MUSER, 4224096Seric 'F', M_NEEDFROM, 4234096Seric 'D', M_NEEDDATE, 4244096Seric 'M', M_MSGID, 4254096Seric 'u', M_USR_UPPER, 4264096Seric 'h', M_HST_UPPER, 4274096Seric 'x', M_FULLNAME, 4284096Seric 'A', M_ARPAFMT, 4295601Seric 'U', M_UGLYUUCP, 4305906Seric 'e', M_EXPENSIVE, 4314319Seric '\0', 0 4324096Seric }; 4334096Seric 4344627Seric u_long 4354627Seric mfencode(p) 4364096Seric register char *p; 4374096Seric { 4384096Seric register struct optlist *o; 4394627Seric register u_long opts = 0; 4404096Seric 4414096Seric while (*p != '\0') 4424096Seric { 4434096Seric for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++) 4444096Seric continue; 4454096Seric if (o->opt_name == '\0') 4464096Seric syserr("bad mailer option %c", *p); 4474096Seric opts |= o->opt_value; 4484096Seric p++; 4494096Seric } 4504096Seric return (opts); 4514096Seric } 4524627Seric /* 4534627Seric ** MFDECODE -- decode mailer flags into external form. 4544627Seric ** 4554627Seric ** Parameters: 4564627Seric ** flags -- value of flags to decode. 4574627Seric ** f -- file to write them onto. 4584627Seric ** 4594627Seric ** Returns: 4604627Seric ** none. 4614627Seric ** 4624627Seric ** Side Effects: 4634627Seric ** none. 4644627Seric */ 4654627Seric 4664627Seric mfdecode(flags, f) 4674627Seric u_long flags; 4684627Seric FILE *f; 4694627Seric { 4704627Seric register struct optlist *o; 4714627Seric 4724627Seric putc('?', f); 4734627Seric for (o = OptList; o->opt_name != '\0'; o++) 4744627Seric { 4754627Seric if ((o->opt_value & flags) == o->opt_value) 4764627Seric { 4774627Seric flags &= ~o->opt_value; 4784627Seric putc(o->opt_name, f); 4794627Seric } 4804627Seric } 4814627Seric putc('?', f); 4824627Seric } 483