13313Seric # include "sendmail.h" 23308Seric 3*7231Seric SCCSID(@(#)readcf.c 3.27 06/19/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]; 61*7231Seric 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 703308Seric while (fgets(buf, sizeof buf, cf) != NULL) 713308Seric { 723308Seric p = rindex(buf, '\n'); 733308Seric if (p != NULL) 743308Seric *p = '\0'; 753308Seric 763308Seric switch (buf[0]) 773308Seric { 783308Seric case '\n': 793308Seric case '\0': 803308Seric case ' ': 813308Seric case '\t': 823308Seric case '#': /* comment */ 833308Seric break; 843308Seric 853308Seric case 'R': /* rewriting rule */ 863308Seric for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 873308Seric continue; 883308Seric 893308Seric if (*p == '\0') 905909Seric { 913308Seric syserr("invalid rewrite line \"%s\"", buf); 925909Seric break; 935909Seric } 945909Seric 955909Seric /* allocate space for the rule header */ 965909Seric if (rwp == NULL) 975909Seric { 985909Seric RewriteRules[ruleset] = rwp = 995909Seric (struct rewrite *) xalloc(sizeof *rwp); 1005909Seric } 1013308Seric else 1023308Seric { 1035909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 1045909Seric rwp = rwp->r_next; 1055909Seric } 1065909Seric rwp->r_next = NULL; 1073308Seric 1085909Seric /* expand and save the LHS */ 1095909Seric *p = '\0'; 1106991Seric expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv); 1115909Seric rwp->r_lhs = prescan(exbuf, '\t'); 1125909Seric if (rwp->r_lhs != NULL) 1135909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 1145909Seric 1155909Seric /* expand and save the RHS */ 1165909Seric while (*++p == '\t') 1175909Seric continue; 118*7231Seric q = p; 119*7231Seric while (*p != '\0' && *p != '\t') 120*7231Seric p++; 121*7231Seric *p = '\0'; 122*7231Seric expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv); 1235909Seric rwp->r_rhs = prescan(exbuf, '\t'); 1245909Seric if (rwp->r_rhs != NULL) 1255909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 1263308Seric break; 1273308Seric 1284072Seric case 'S': /* select rewriting set */ 1294072Seric ruleset = atoi(&buf[1]); 1304072Seric rwp = NULL; 1314072Seric break; 1324072Seric 1333308Seric case 'D': /* macro definition */ 1343308Seric define(buf[1], newstr(&buf[2])); 1353308Seric break; 1363308Seric 1373387Seric case 'H': /* required header line */ 1384088Seric (void) chompheader(&buf[1], TRUE); 1393387Seric break; 1403387Seric 1414061Seric case 'C': /* word class */ 1424432Seric case 'F': /* word class from file */ 1434061Seric class = buf[1]; 1444061Seric if (!isalpha(class)) 1454061Seric goto badline; 1464061Seric if (isupper(class)) 1474061Seric class -= 'A'; 1484061Seric else 1494061Seric class -= 'a'; 1504432Seric 1514432Seric /* read list of words from argument or file */ 1524432Seric if (buf[0] == 'F') 1534432Seric { 1544432Seric /* read from file */ 1554432Seric for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 1564432Seric continue; 1574432Seric if (*p == '\0') 1584432Seric p = "%s"; 1594432Seric else 1604432Seric { 1614432Seric *p = '\0'; 1624432Seric while (isspace(*++p)) 1634432Seric continue; 1644432Seric } 1654432Seric fileclass(class, &buf[2], p); 1664432Seric break; 1674432Seric } 1684061Seric 1694432Seric /* scan the list of words and set class for all */ 1704061Seric for (p = &buf[2]; *p != '\0'; ) 1714061Seric { 1724061Seric register char *wd; 1734061Seric char delim; 1744061Seric register STAB *s; 1754061Seric 1764061Seric while (*p != '\0' && isspace(*p)) 1774061Seric p++; 1784061Seric wd = p; 1794061Seric while (*p != '\0' && !isspace(*p)) 1804061Seric p++; 1814061Seric delim = *p; 1824061Seric *p = '\0'; 1834061Seric if (wd[0] != '\0') 1844061Seric { 1854103Seric s = stab(wd, ST_CLASS, ST_ENTER); 1866275Seric s->s_class |= 1L << class; 1874061Seric } 1884061Seric *p = delim; 1894061Seric } 1904061Seric break; 1914061Seric 1924096Seric case 'M': /* define mailer */ 1934217Seric makemailer(&buf[1], safe); 1944096Seric break; 1954096Seric 1963308Seric default: 1974061Seric badline: 1983308Seric syserr("unknown control line \"%s\"", buf); 1993308Seric } 2003308Seric } 2014096Seric } 2024096Seric /* 2034432Seric ** FILECLASS -- read members of a class from a file 2044432Seric ** 2054432Seric ** Parameters: 2064432Seric ** class -- class to define. 2074432Seric ** filename -- name of file to read. 2084432Seric ** fmt -- scanf string to use for match. 2094432Seric ** 2104432Seric ** Returns: 2114432Seric ** none 2124432Seric ** 2134432Seric ** Side Effects: 2144432Seric ** 2154432Seric ** puts all lines in filename that match a scanf into 2164432Seric ** the named class. 2174432Seric */ 2184432Seric 2194432Seric fileclass(class, filename, fmt) 2204432Seric int class; 2214432Seric char *filename; 2224432Seric char *fmt; 2234432Seric { 2244432Seric register FILE *f; 2254432Seric char buf[MAXLINE]; 2264432Seric 2274432Seric f = fopen(filename, "r"); 2284432Seric if (f == NULL) 2294432Seric { 2304432Seric syserr("cannot open %s", filename); 2314432Seric return; 2324432Seric } 2334432Seric 2344432Seric while (fgets(buf, sizeof buf, f) != NULL) 2354432Seric { 2364432Seric register STAB *s; 2374432Seric char wordbuf[MAXNAME+1]; 2384432Seric 2394432Seric if (sscanf(buf, fmt, wordbuf) != 1) 2404432Seric continue; 2414432Seric s = stab(wordbuf, ST_CLASS, ST_ENTER); 2426275Seric s->s_class |= 1L << class; 2434432Seric } 2444432Seric 2454627Seric (void) fclose(f); 2464432Seric } 2474432Seric /* 2484096Seric ** MAKEMAILER -- define a new mailer. 2494096Seric ** 2504096Seric ** Parameters: 2514096Seric ** line -- description of mailer. This is in tokens 2524096Seric ** separated by white space. The fields are: 2534096Seric ** * the name of the mailer, as refered to 2544096Seric ** in the rewriting rules. 2554096Seric ** * the pathname of the program to fork to 2564096Seric ** execute it. 2574096Seric ** * the options needed by this program. 2584096Seric ** * the macro string needed to translate 2594096Seric ** a local "from" name to one that can be 2604096Seric ** returned to this machine. 2614096Seric ** * the argument vector (a series of parameters). 2624217Seric ** safe -- set if this is a safe configuration file. 2634096Seric ** 2644096Seric ** Returns: 2654096Seric ** none. 2664096Seric ** 2674096Seric ** Side Effects: 2684096Seric ** enters the mailer into the mailer table. 2694096Seric */ 2703308Seric 2714096Seric # define SETWORD \ 2724096Seric { \ 2734096Seric while (*p != '\0' && isspace(*p)) \ 2744096Seric p++; \ 2754096Seric q = p; \ 2764096Seric while (*p != '\0' && !isspace(*p)) \ 2774096Seric p++; \ 2784096Seric if (*p != '\0') \ 2794096Seric *p++ = '\0'; \ 2804096Seric } 2814096Seric 2824217Seric makemailer(line, safe) 2834096Seric char *line; 2844217Seric bool safe; 2854096Seric { 2864096Seric register char *p; 2874096Seric register char *q; 2884096Seric char *mname; 2894096Seric char *mpath; 2904627Seric u_long mopts; 2914627Seric extern u_long mfencode(); 2924096Seric char *mfrom; 2934096Seric register struct mailer *m; 2944096Seric char *margv[MAXPV + 1]; 2954096Seric register int i; 2964096Seric extern int NextMailer; 2974439Seric STAB *s; 2984096Seric 2994096Seric if (NextMailer >= MAXMAILERS) 3004096Seric { 3014096Seric syserr("Too many mailers defined"); 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; 3164096Seric mfrom = q; 3174096Seric 3184096Seric if (*p == '\0') 3194096Seric { 3204096Seric syserr("invalid M line in configuration file"); 3214096Seric return; 3224096Seric } 3234096Seric 3244096Seric /* allocate a mailer */ 3254096Seric m = (struct mailer *) xalloc(sizeof *m); 3264096Seric m->m_name = newstr(mname); 3274096Seric m->m_mailer = newstr(mpath); 3284096Seric m->m_flags = mopts; 3294096Seric m->m_from = newstr(mfrom); 3304096Seric m->m_badstat = EX_UNAVAILABLE; 3314439Seric m->m_mno = NextMailer; 3324096Seric Mailer[NextMailer++] = m; 3334096Seric 3344096Seric /* collect the argument vector */ 3354096Seric for (i = 0; i < MAXPV - 1 && *p != '\0'; i++) 3364096Seric { 3374096Seric SETWORD; 3384096Seric margv[i] = newstr(q); 3394096Seric } 3404096Seric margv[i++] = NULL; 3414096Seric 3424096Seric /* save the argv */ 3437009Seric m->m_argv = (char **) xalloc(sizeof margv[0] * i); 3444096Seric bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i); 3454439Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 3464439Seric s->s_mailer = m; 3473308Seric } 3483308Seric /* 3493308Seric ** PRINTRULES -- print rewrite rules (for debugging) 3503308Seric ** 3513308Seric ** Parameters: 3523308Seric ** none. 3533308Seric ** 3543308Seric ** Returns: 3553308Seric ** none. 3563308Seric ** 3573308Seric ** Side Effects: 3583308Seric ** prints rewrite rules. 3593308Seric */ 3603308Seric 3614319Seric # ifdef DEBUG 3624319Seric 3633308Seric printrules() 3643308Seric { 3653308Seric register struct rewrite *rwp; 3664072Seric register int ruleset; 3673308Seric 3684072Seric for (ruleset = 0; ruleset < 10; ruleset++) 3693308Seric { 3704072Seric if (RewriteRules[ruleset] == NULL) 3714072Seric continue; 3724072Seric printf("\n----Rule Set %d:\n", ruleset); 3733308Seric 3744072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 3753308Seric { 3764072Seric register char **av; 3774072Seric 3784072Seric printf("\n"); 3794072Seric for (av = rwp->r_lhs; *av != NULL; av++) 3804072Seric { 3814072Seric xputs(*av); 3824072Seric putchar('_'); 3834072Seric } 3844072Seric printf("\n\t"); 3854072Seric for (av = rwp->r_rhs; *av != NULL; av++) 3864072Seric { 3874072Seric xputs(*av); 3884072Seric putchar('_'); 3894072Seric } 3904072Seric printf("\n"); 3913308Seric } 3923308Seric } 3933308Seric } 3944319Seric 3954319Seric # endif DEBUG 3964096Seric /* 3974627Seric ** MFENCODE -- crack mailer options 3984096Seric ** 3994096Seric ** These options modify the functioning of the mailer 4004096Seric ** from the configuration table. 4014096Seric ** 4024096Seric ** Parameters: 4034096Seric ** p -- pointer to vector of options. 4044096Seric ** 4054096Seric ** Returns: 4064096Seric ** option list in binary. 4074096Seric ** 4084096Seric ** Side Effects: 4094096Seric ** none. 4104096Seric */ 4114096Seric 4124096Seric struct optlist 4134096Seric { 4144096Seric char opt_name; /* external name of option */ 4156275Seric u_long opt_value; /* internal name of option */ 4164096Seric }; 4174096Seric struct optlist OptList[] = 4184096Seric { 4194096Seric 'f', M_FOPT, 4204096Seric 'r', M_ROPT, 4214096Seric 'q', M_QUIET, 4224096Seric 'S', M_RESTR, 4234096Seric 'n', M_NHDR, 4244197Seric 'l', M_LOCAL, 4254096Seric 's', M_STRIPQ, 4264096Seric 'm', M_MUSER, 4274096Seric 'F', M_NEEDFROM, 4284096Seric 'D', M_NEEDDATE, 4294096Seric 'M', M_MSGID, 4304096Seric 'u', M_USR_UPPER, 4314096Seric 'h', M_HST_UPPER, 4324096Seric 'x', M_FULLNAME, 4334096Seric 'A', M_ARPAFMT, 4345601Seric 'U', M_UGLYUUCP, 4355906Seric 'e', M_EXPENSIVE, 4366821Seric 'R', M_RELRCPT, 4376983Seric 'X', M_FULLSMTP, 4384319Seric '\0', 0 4394096Seric }; 4404096Seric 4414627Seric u_long 4424627Seric mfencode(p) 4434096Seric register char *p; 4444096Seric { 4454096Seric register struct optlist *o; 4464627Seric register u_long opts = 0; 4474096Seric 4484096Seric while (*p != '\0') 4494096Seric { 4504096Seric for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++) 4514096Seric continue; 4524096Seric if (o->opt_name == '\0') 4534096Seric syserr("bad mailer option %c", *p); 4544096Seric opts |= o->opt_value; 4554096Seric p++; 4564096Seric } 4574096Seric return (opts); 4584096Seric } 4594627Seric /* 4604627Seric ** MFDECODE -- decode mailer flags into external form. 4614627Seric ** 4624627Seric ** Parameters: 4634627Seric ** flags -- value of flags to decode. 4644627Seric ** f -- file to write them onto. 4654627Seric ** 4664627Seric ** Returns: 4674627Seric ** none. 4684627Seric ** 4694627Seric ** Side Effects: 4704627Seric ** none. 4714627Seric */ 4724627Seric 4734627Seric mfdecode(flags, f) 4744627Seric u_long flags; 4754627Seric FILE *f; 4764627Seric { 4774627Seric register struct optlist *o; 4784627Seric 4794627Seric putc('?', f); 4804627Seric for (o = OptList; o->opt_name != '\0'; o++) 4814627Seric { 4824627Seric if ((o->opt_value & flags) == o->opt_value) 4834627Seric { 4844627Seric flags &= ~o->opt_value; 4854627Seric putc(o->opt_name, f); 4864627Seric } 4874627Seric } 4884627Seric putc('?', f); 4894627Seric } 490