13313Seric # include "sendmail.h" 23308Seric 3*7854Seric SCCSID(@(#)readcf.c 3.28 08/23/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; 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 70*7854Seric while (fgetfolded(buf, sizeof buf, cf) != NULL) 713308Seric { 723308Seric switch (buf[0]) 733308Seric { 743308Seric case '\0': 753308Seric case '#': /* comment */ 763308Seric break; 773308Seric 783308Seric case 'R': /* rewriting rule */ 793308Seric for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 803308Seric continue; 813308Seric 823308Seric if (*p == '\0') 835909Seric { 843308Seric syserr("invalid rewrite line \"%s\"", buf); 855909Seric break; 865909Seric } 875909Seric 885909Seric /* allocate space for the rule header */ 895909Seric if (rwp == NULL) 905909Seric { 915909Seric RewriteRules[ruleset] = rwp = 925909Seric (struct rewrite *) xalloc(sizeof *rwp); 935909Seric } 943308Seric else 953308Seric { 965909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 975909Seric rwp = rwp->r_next; 985909Seric } 995909Seric rwp->r_next = NULL; 1003308Seric 1015909Seric /* expand and save the LHS */ 1025909Seric *p = '\0'; 1036991Seric expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv); 1045909Seric rwp->r_lhs = prescan(exbuf, '\t'); 1055909Seric if (rwp->r_lhs != NULL) 1065909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 1075909Seric 1085909Seric /* expand and save the RHS */ 1095909Seric while (*++p == '\t') 1105909Seric continue; 1117231Seric q = p; 1127231Seric while (*p != '\0' && *p != '\t') 1137231Seric p++; 1147231Seric *p = '\0'; 1157231Seric expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv); 1165909Seric rwp->r_rhs = prescan(exbuf, '\t'); 1175909Seric if (rwp->r_rhs != NULL) 1185909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 1193308Seric break; 1203308Seric 1214072Seric case 'S': /* select rewriting set */ 1224072Seric ruleset = atoi(&buf[1]); 1234072Seric rwp = NULL; 1244072Seric break; 1254072Seric 1263308Seric case 'D': /* macro definition */ 1273308Seric define(buf[1], newstr(&buf[2])); 1283308Seric break; 1293308Seric 1303387Seric case 'H': /* required header line */ 1314088Seric (void) chompheader(&buf[1], TRUE); 1323387Seric break; 1333387Seric 1344061Seric case 'C': /* word class */ 1354432Seric case 'F': /* word class from file */ 1364061Seric class = buf[1]; 1374061Seric if (!isalpha(class)) 1384061Seric goto badline; 1394061Seric if (isupper(class)) 1404061Seric class -= 'A'; 1414061Seric else 1424061Seric class -= 'a'; 1434432Seric 1444432Seric /* read list of words from argument or file */ 1454432Seric if (buf[0] == 'F') 1464432Seric { 1474432Seric /* read from file */ 1484432Seric for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 1494432Seric continue; 1504432Seric if (*p == '\0') 1514432Seric p = "%s"; 1524432Seric else 1534432Seric { 1544432Seric *p = '\0'; 1554432Seric while (isspace(*++p)) 1564432Seric continue; 1574432Seric } 1584432Seric fileclass(class, &buf[2], p); 1594432Seric break; 1604432Seric } 1614061Seric 1624432Seric /* scan the list of words and set class for all */ 1634061Seric for (p = &buf[2]; *p != '\0'; ) 1644061Seric { 1654061Seric register char *wd; 1664061Seric char delim; 1674061Seric register STAB *s; 1684061Seric 1694061Seric while (*p != '\0' && isspace(*p)) 1704061Seric p++; 1714061Seric wd = p; 1724061Seric while (*p != '\0' && !isspace(*p)) 1734061Seric p++; 1744061Seric delim = *p; 1754061Seric *p = '\0'; 1764061Seric if (wd[0] != '\0') 1774061Seric { 1784103Seric s = stab(wd, ST_CLASS, ST_ENTER); 1796275Seric s->s_class |= 1L << class; 1804061Seric } 1814061Seric *p = delim; 1824061Seric } 1834061Seric break; 1844061Seric 1854096Seric case 'M': /* define mailer */ 1864217Seric makemailer(&buf[1], safe); 1874096Seric break; 1884096Seric 1893308Seric default: 1904061Seric badline: 1913308Seric syserr("unknown control line \"%s\"", buf); 1923308Seric } 1933308Seric } 1944096Seric } 1954096Seric /* 1964432Seric ** FILECLASS -- read members of a class from a file 1974432Seric ** 1984432Seric ** Parameters: 1994432Seric ** class -- class to define. 2004432Seric ** filename -- name of file to read. 2014432Seric ** fmt -- scanf string to use for match. 2024432Seric ** 2034432Seric ** Returns: 2044432Seric ** none 2054432Seric ** 2064432Seric ** Side Effects: 2074432Seric ** 2084432Seric ** puts all lines in filename that match a scanf into 2094432Seric ** the named class. 2104432Seric */ 2114432Seric 2124432Seric fileclass(class, filename, fmt) 2134432Seric int class; 2144432Seric char *filename; 2154432Seric char *fmt; 2164432Seric { 2174432Seric register FILE *f; 2184432Seric char buf[MAXLINE]; 2194432Seric 2204432Seric f = fopen(filename, "r"); 2214432Seric if (f == NULL) 2224432Seric { 2234432Seric syserr("cannot open %s", filename); 2244432Seric return; 2254432Seric } 2264432Seric 2274432Seric while (fgets(buf, sizeof buf, f) != NULL) 2284432Seric { 2294432Seric register STAB *s; 2304432Seric char wordbuf[MAXNAME+1]; 2314432Seric 2324432Seric if (sscanf(buf, fmt, wordbuf) != 1) 2334432Seric continue; 2344432Seric s = stab(wordbuf, ST_CLASS, ST_ENTER); 2356275Seric s->s_class |= 1L << class; 2364432Seric } 2374432Seric 2384627Seric (void) fclose(f); 2394432Seric } 2404432Seric /* 2414096Seric ** MAKEMAILER -- define a new mailer. 2424096Seric ** 2434096Seric ** Parameters: 2444096Seric ** line -- description of mailer. This is in tokens 2454096Seric ** separated by white space. The fields are: 2464096Seric ** * the name of the mailer, as refered to 2474096Seric ** in the rewriting rules. 2484096Seric ** * the pathname of the program to fork to 2494096Seric ** execute it. 2504096Seric ** * the options needed by this program. 2514096Seric ** * the macro string needed to translate 2524096Seric ** a local "from" name to one that can be 2534096Seric ** returned to this machine. 2544096Seric ** * the argument vector (a series of parameters). 2554217Seric ** safe -- set if this is a safe configuration file. 2564096Seric ** 2574096Seric ** Returns: 2584096Seric ** none. 2594096Seric ** 2604096Seric ** Side Effects: 2614096Seric ** enters the mailer into the mailer table. 2624096Seric */ 2633308Seric 2644096Seric # define SETWORD \ 2654096Seric { \ 2664096Seric while (*p != '\0' && isspace(*p)) \ 2674096Seric p++; \ 2684096Seric q = p; \ 2694096Seric while (*p != '\0' && !isspace(*p)) \ 2704096Seric p++; \ 2714096Seric if (*p != '\0') \ 2724096Seric *p++ = '\0'; \ 2734096Seric } 2744096Seric 2754217Seric makemailer(line, safe) 2764096Seric char *line; 2774217Seric bool safe; 2784096Seric { 2794096Seric register char *p; 2804096Seric register char *q; 2814096Seric char *mname; 2824096Seric char *mpath; 2834627Seric u_long mopts; 2844627Seric extern u_long mfencode(); 2854096Seric char *mfrom; 2864096Seric register struct mailer *m; 2874096Seric char *margv[MAXPV + 1]; 2884096Seric register int i; 2894096Seric extern int NextMailer; 2904439Seric STAB *s; 2914096Seric 2924096Seric if (NextMailer >= MAXMAILERS) 2934096Seric { 2944096Seric syserr("Too many mailers defined"); 2954096Seric return; 2964096Seric } 2974096Seric 2984096Seric /* collect initial information */ 2994096Seric p = line; 3004096Seric SETWORD; 3014096Seric mname = q; 3024096Seric SETWORD; 3034096Seric mpath = q; 3044096Seric SETWORD; 3054627Seric mopts = mfencode(q); 3064217Seric if (!safe) 3074217Seric mopts &= ~M_RESTR; 3084096Seric SETWORD; 3094096Seric mfrom = q; 3104096Seric 3114096Seric if (*p == '\0') 3124096Seric { 3134096Seric syserr("invalid M line in configuration file"); 3144096Seric return; 3154096Seric } 3164096Seric 3174096Seric /* allocate a mailer */ 3184096Seric m = (struct mailer *) xalloc(sizeof *m); 3194096Seric m->m_name = newstr(mname); 3204096Seric m->m_mailer = newstr(mpath); 3214096Seric m->m_flags = mopts; 3224096Seric m->m_from = newstr(mfrom); 3234096Seric m->m_badstat = EX_UNAVAILABLE; 3244439Seric m->m_mno = NextMailer; 3254096Seric Mailer[NextMailer++] = m; 3264096Seric 3274096Seric /* collect the argument vector */ 3284096Seric for (i = 0; i < MAXPV - 1 && *p != '\0'; i++) 3294096Seric { 3304096Seric SETWORD; 3314096Seric margv[i] = newstr(q); 3324096Seric } 3334096Seric margv[i++] = NULL; 3344096Seric 3354096Seric /* save the argv */ 3367009Seric m->m_argv = (char **) xalloc(sizeof margv[0] * i); 3374096Seric bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i); 3384439Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 3394439Seric s->s_mailer = m; 3403308Seric } 3413308Seric /* 3423308Seric ** PRINTRULES -- print rewrite rules (for debugging) 3433308Seric ** 3443308Seric ** Parameters: 3453308Seric ** none. 3463308Seric ** 3473308Seric ** Returns: 3483308Seric ** none. 3493308Seric ** 3503308Seric ** Side Effects: 3513308Seric ** prints rewrite rules. 3523308Seric */ 3533308Seric 3544319Seric # ifdef DEBUG 3554319Seric 3563308Seric printrules() 3573308Seric { 3583308Seric register struct rewrite *rwp; 3594072Seric register int ruleset; 3603308Seric 3614072Seric for (ruleset = 0; ruleset < 10; ruleset++) 3623308Seric { 3634072Seric if (RewriteRules[ruleset] == NULL) 3644072Seric continue; 3654072Seric printf("\n----Rule Set %d:\n", ruleset); 3663308Seric 3674072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 3683308Seric { 3694072Seric register char **av; 3704072Seric 3714072Seric printf("\n"); 3724072Seric for (av = rwp->r_lhs; *av != NULL; av++) 3734072Seric { 3744072Seric xputs(*av); 3754072Seric putchar('_'); 3764072Seric } 3774072Seric printf("\n\t"); 3784072Seric for (av = rwp->r_rhs; *av != NULL; av++) 3794072Seric { 3804072Seric xputs(*av); 3814072Seric putchar('_'); 3824072Seric } 3834072Seric printf("\n"); 3843308Seric } 3853308Seric } 3863308Seric } 3874319Seric 3884319Seric # endif DEBUG 3894096Seric /* 3904627Seric ** MFENCODE -- crack mailer options 3914096Seric ** 3924096Seric ** These options modify the functioning of the mailer 3934096Seric ** from the configuration table. 3944096Seric ** 3954096Seric ** Parameters: 3964096Seric ** p -- pointer to vector of options. 3974096Seric ** 3984096Seric ** Returns: 3994096Seric ** option list in binary. 4004096Seric ** 4014096Seric ** Side Effects: 4024096Seric ** none. 4034096Seric */ 4044096Seric 4054096Seric struct optlist 4064096Seric { 4074096Seric char opt_name; /* external name of option */ 4086275Seric u_long opt_value; /* internal name of option */ 4094096Seric }; 4104096Seric struct optlist OptList[] = 4114096Seric { 4124096Seric 'f', M_FOPT, 4134096Seric 'r', M_ROPT, 4144096Seric 'q', M_QUIET, 4154096Seric 'S', M_RESTR, 4164096Seric 'n', M_NHDR, 4174197Seric 'l', M_LOCAL, 4184096Seric 's', M_STRIPQ, 4194096Seric 'm', M_MUSER, 4204096Seric 'F', M_NEEDFROM, 4214096Seric 'D', M_NEEDDATE, 4224096Seric 'M', M_MSGID, 4234096Seric 'u', M_USR_UPPER, 4244096Seric 'h', M_HST_UPPER, 4254096Seric 'x', M_FULLNAME, 4264096Seric 'A', M_ARPAFMT, 4275601Seric 'U', M_UGLYUUCP, 4285906Seric 'e', M_EXPENSIVE, 4296821Seric 'R', M_RELRCPT, 4306983Seric 'X', M_FULLSMTP, 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