13313Seric # include "sendmail.h" 23308Seric 3*4627Seric static char SccsId[] = "@(#)readcf.c 3.16 10/26/81"; 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; 603308Seric 613308Seric cf = fopen(cfname, "r"); 623308Seric if (cf == NULL) 633308Seric { 643308Seric syserr("cannot open %s", cfname); 653308Seric exit(EX_OSFILE); 663308Seric } 673308Seric 683308Seric while (fgets(buf, sizeof buf, cf) != NULL) 693308Seric { 703308Seric p = rindex(buf, '\n'); 713308Seric if (p != NULL) 723308Seric *p = '\0'; 733308Seric 743308Seric switch (buf[0]) 753308Seric { 763308Seric case '\n': 773308Seric case '\0': 783308Seric case ' ': 793308Seric case '\t': 803308Seric case '#': /* comment */ 813308Seric break; 823308Seric 833308Seric case 'R': /* rewriting rule */ 843308Seric for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 853308Seric continue; 863308Seric 873308Seric if (*p == '\0') 883308Seric syserr("invalid rewrite line \"%s\"", buf); 893308Seric else 903308Seric { 913308Seric if (rwp == NULL) 924072Seric { 934072Seric RewriteRules[ruleset] = rwp = 944072Seric (struct rewrite *) xalloc(sizeof *rwp); 954072Seric } 963308Seric else 973308Seric { 983308Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 993308Seric rwp = rwp->r_next; 1003308Seric } 1013308Seric rwp->r_next = NULL; 1023308Seric 1033308Seric rwp->r_lhs = prescan(&buf[1], '\t'); 1043308Seric if (rwp->r_lhs != NULL) 1053308Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 1063308Seric while (*p == '\t') 1073308Seric p++; 1083308Seric rwp->r_rhs = prescan(p, '\t'); 1093308Seric if (rwp->r_rhs != NULL) 1103308Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 1113308Seric } 1123308Seric break; 1133308Seric 1144072Seric case 'S': /* select rewriting set */ 1154072Seric ruleset = atoi(&buf[1]); 1164072Seric rwp = NULL; 1174072Seric break; 1184072Seric 1193308Seric case 'D': /* macro definition */ 1203308Seric define(buf[1], newstr(&buf[2])); 1213308Seric break; 1223308Seric 1233387Seric case 'H': /* required header line */ 1244088Seric (void) chompheader(&buf[1], TRUE); 1253387Seric break; 1263387Seric 1274061Seric case 'C': /* word class */ 1284432Seric case 'F': /* word class from file */ 1294061Seric class = buf[1]; 1304061Seric if (!isalpha(class)) 1314061Seric goto badline; 1324061Seric if (isupper(class)) 1334061Seric class -= 'A'; 1344061Seric else 1354061Seric class -= 'a'; 1364432Seric 1374432Seric /* read list of words from argument or file */ 1384432Seric if (buf[0] == 'F') 1394432Seric { 1404432Seric /* read from file */ 1414432Seric for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 1424432Seric continue; 1434432Seric if (*p == '\0') 1444432Seric p = "%s"; 1454432Seric else 1464432Seric { 1474432Seric *p = '\0'; 1484432Seric while (isspace(*++p)) 1494432Seric continue; 1504432Seric } 1514432Seric fileclass(class, &buf[2], p); 1524432Seric break; 1534432Seric } 1544061Seric 1554432Seric /* scan the list of words and set class for all */ 1564061Seric for (p = &buf[2]; *p != '\0'; ) 1574061Seric { 1584061Seric register char *wd; 1594061Seric char delim; 1604061Seric register STAB *s; 1614061Seric 1624061Seric while (*p != '\0' && isspace(*p)) 1634061Seric p++; 1644061Seric wd = p; 1654061Seric while (*p != '\0' && !isspace(*p)) 1664061Seric p++; 1674061Seric delim = *p; 1684061Seric *p = '\0'; 1694061Seric if (wd[0] != '\0') 1704061Seric { 1714103Seric s = stab(wd, ST_CLASS, ST_ENTER); 1724061Seric s->s_class |= 1 << class; 1734061Seric } 1744061Seric *p = delim; 1754061Seric } 1764061Seric break; 1774061Seric 1784096Seric case 'M': /* define mailer */ 1794217Seric makemailer(&buf[1], safe); 1804096Seric break; 1814096Seric 1823308Seric default: 1834061Seric badline: 1843308Seric syserr("unknown control line \"%s\"", buf); 1853308Seric } 1863308Seric } 1874096Seric } 1884096Seric /* 1894432Seric ** FILECLASS -- read members of a class from a file 1904432Seric ** 1914432Seric ** Parameters: 1924432Seric ** class -- class to define. 1934432Seric ** filename -- name of file to read. 1944432Seric ** fmt -- scanf string to use for match. 1954432Seric ** 1964432Seric ** Returns: 1974432Seric ** none 1984432Seric ** 1994432Seric ** Side Effects: 2004432Seric ** 2014432Seric ** puts all lines in filename that match a scanf into 2024432Seric ** the named class. 2034432Seric */ 2044432Seric 2054432Seric fileclass(class, filename, fmt) 2064432Seric int class; 2074432Seric char *filename; 2084432Seric char *fmt; 2094432Seric { 2104432Seric register FILE *f; 2114432Seric char buf[MAXLINE]; 2124432Seric 2134432Seric f = fopen(filename, "r"); 2144432Seric if (f == NULL) 2154432Seric { 2164432Seric syserr("cannot open %s", filename); 2174432Seric return; 2184432Seric } 2194432Seric 2204432Seric while (fgets(buf, sizeof buf, f) != NULL) 2214432Seric { 2224432Seric register STAB *s; 2234432Seric char wordbuf[MAXNAME+1]; 2244432Seric 2254432Seric if (sscanf(buf, fmt, wordbuf) != 1) 2264432Seric continue; 2274432Seric s = stab(wordbuf, ST_CLASS, ST_ENTER); 2284432Seric s->s_class |= 1 << class; 2294432Seric } 2304432Seric 231*4627Seric (void) fclose(f); 2324432Seric } 2334432Seric /* 2344096Seric ** MAKEMAILER -- define a new mailer. 2354096Seric ** 2364096Seric ** Parameters: 2374096Seric ** line -- description of mailer. This is in tokens 2384096Seric ** separated by white space. The fields are: 2394096Seric ** * the name of the mailer, as refered to 2404096Seric ** in the rewriting rules. 2414096Seric ** * the pathname of the program to fork to 2424096Seric ** execute it. 2434096Seric ** * the options needed by this program. 2444096Seric ** * the macro string needed to translate 2454096Seric ** a local "from" name to one that can be 2464096Seric ** returned to this machine. 2474096Seric ** * the argument vector (a series of parameters). 2484217Seric ** safe -- set if this is a safe configuration file. 2494096Seric ** 2504096Seric ** Returns: 2514096Seric ** none. 2524096Seric ** 2534096Seric ** Side Effects: 2544096Seric ** enters the mailer into the mailer table. 2554096Seric */ 2563308Seric 2574096Seric # define SETWORD \ 2584096Seric { \ 2594096Seric while (*p != '\0' && isspace(*p)) \ 2604096Seric p++; \ 2614096Seric q = p; \ 2624096Seric while (*p != '\0' && !isspace(*p)) \ 2634096Seric p++; \ 2644096Seric if (*p != '\0') \ 2654096Seric *p++ = '\0'; \ 2664096Seric } 2674096Seric 2684217Seric makemailer(line, safe) 2694096Seric char *line; 2704217Seric bool safe; 2714096Seric { 2724096Seric register char *p; 2734096Seric register char *q; 2744096Seric char *mname; 2754096Seric char *mpath; 276*4627Seric u_long mopts; 277*4627Seric extern u_long mfencode(); 2784096Seric char *mfrom; 2794096Seric register struct mailer *m; 2804096Seric char *margv[MAXPV + 1]; 2814096Seric register int i; 2824096Seric extern int NextMailer; 2834439Seric STAB *s; 2844096Seric 2854096Seric if (NextMailer >= MAXMAILERS) 2864096Seric { 2874096Seric syserr("Too many mailers defined"); 2884096Seric return; 2894096Seric } 2904096Seric 2914096Seric /* collect initial information */ 2924096Seric p = line; 2934096Seric SETWORD; 2944096Seric mname = q; 2954096Seric SETWORD; 2964096Seric mpath = q; 2974096Seric SETWORD; 298*4627Seric mopts = mfencode(q); 2994217Seric if (!safe) 3004217Seric mopts &= ~M_RESTR; 3014096Seric SETWORD; 3024096Seric mfrom = q; 3034096Seric 3044096Seric if (*p == '\0') 3054096Seric { 3064096Seric syserr("invalid M line in configuration file"); 3074096Seric return; 3084096Seric } 3094096Seric 3104096Seric /* allocate a mailer */ 3114096Seric m = (struct mailer *) xalloc(sizeof *m); 3124096Seric m->m_name = newstr(mname); 3134096Seric m->m_mailer = newstr(mpath); 3144096Seric m->m_flags = mopts; 3154096Seric m->m_from = newstr(mfrom); 3164096Seric m->m_badstat = EX_UNAVAILABLE; 3174096Seric m->m_sendq = NULL; 3184439Seric m->m_mno = NextMailer; 3194096Seric Mailer[NextMailer++] = m; 3204096Seric 3214096Seric /* collect the argument vector */ 3224096Seric for (i = 0; i < MAXPV - 1 && *p != '\0'; i++) 3234096Seric { 3244096Seric SETWORD; 3254096Seric margv[i] = newstr(q); 3264096Seric } 3274096Seric margv[i++] = NULL; 3284096Seric 3294096Seric /* save the argv */ 3304319Seric m->m_argv = (char **) xalloc((unsigned) (sizeof margv[0] * i)); 3314096Seric bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i); 3324439Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 3334439Seric s->s_mailer = m; 3343308Seric } 3353308Seric /* 3363308Seric ** PRINTRULES -- print rewrite rules (for debugging) 3373308Seric ** 3383308Seric ** Parameters: 3393308Seric ** none. 3403308Seric ** 3413308Seric ** Returns: 3423308Seric ** none. 3433308Seric ** 3443308Seric ** Side Effects: 3453308Seric ** prints rewrite rules. 3463308Seric */ 3473308Seric 3484319Seric # ifdef DEBUG 3494319Seric 3503308Seric printrules() 3513308Seric { 3523308Seric register struct rewrite *rwp; 3534072Seric register int ruleset; 3543308Seric 3554072Seric for (ruleset = 0; ruleset < 10; ruleset++) 3563308Seric { 3574072Seric if (RewriteRules[ruleset] == NULL) 3584072Seric continue; 3594072Seric printf("\n----Rule Set %d:\n", ruleset); 3603308Seric 3614072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 3623308Seric { 3634072Seric register char **av; 3644072Seric 3654072Seric printf("\n"); 3664072Seric for (av = rwp->r_lhs; *av != NULL; av++) 3674072Seric { 3684072Seric xputs(*av); 3694072Seric putchar('_'); 3704072Seric } 3714072Seric printf("\n\t"); 3724072Seric for (av = rwp->r_rhs; *av != NULL; av++) 3734072Seric { 3744072Seric xputs(*av); 3754072Seric putchar('_'); 3764072Seric } 3774072Seric printf("\n"); 3783308Seric } 3793308Seric } 3803308Seric } 3814319Seric 3824319Seric # endif DEBUG 3834096Seric /* 384*4627Seric ** MFENCODE -- crack mailer options 3854096Seric ** 3864096Seric ** These options modify the functioning of the mailer 3874096Seric ** from the configuration table. 3884096Seric ** 3894096Seric ** Parameters: 3904096Seric ** p -- pointer to vector of options. 3914096Seric ** 3924096Seric ** Returns: 3934096Seric ** option list in binary. 3944096Seric ** 3954096Seric ** Side Effects: 3964096Seric ** none. 3974096Seric */ 3984096Seric 3994096Seric struct optlist 4004096Seric { 4014096Seric char opt_name; /* external name of option */ 4024096Seric int opt_value; /* internal name of option */ 4034096Seric }; 4044096Seric struct optlist OptList[] = 4054096Seric { 4064096Seric 'f', M_FOPT, 4074096Seric 'r', M_ROPT, 4084096Seric 'q', M_QUIET, 4094096Seric 'S', M_RESTR, 4104096Seric 'n', M_NHDR, 4114197Seric 'l', M_LOCAL, 4124096Seric 's', M_STRIPQ, 4134096Seric 'm', M_MUSER, 4144096Seric 'F', M_NEEDFROM, 4154096Seric 'D', M_NEEDDATE, 4164096Seric 'M', M_MSGID, 4174096Seric 'u', M_USR_UPPER, 4184096Seric 'h', M_HST_UPPER, 4194096Seric 'x', M_FULLNAME, 4204096Seric 'A', M_ARPAFMT, 4214319Seric '\0', 0 4224096Seric }; 4234096Seric 424*4627Seric u_long 425*4627Seric mfencode(p) 4264096Seric register char *p; 4274096Seric { 4284096Seric register struct optlist *o; 429*4627Seric register u_long opts = 0; 4304096Seric 4314096Seric while (*p != '\0') 4324096Seric { 4334096Seric for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++) 4344096Seric continue; 4354096Seric if (o->opt_name == '\0') 4364096Seric syserr("bad mailer option %c", *p); 4374096Seric opts |= o->opt_value; 4384096Seric p++; 4394096Seric } 4404096Seric return (opts); 4414096Seric } 442*4627Seric /* 443*4627Seric ** MFDECODE -- decode mailer flags into external form. 444*4627Seric ** 445*4627Seric ** Parameters: 446*4627Seric ** flags -- value of flags to decode. 447*4627Seric ** f -- file to write them onto. 448*4627Seric ** 449*4627Seric ** Returns: 450*4627Seric ** none. 451*4627Seric ** 452*4627Seric ** Side Effects: 453*4627Seric ** none. 454*4627Seric */ 455*4627Seric 456*4627Seric mfdecode(flags, f) 457*4627Seric u_long flags; 458*4627Seric FILE *f; 459*4627Seric { 460*4627Seric register struct optlist *o; 461*4627Seric 462*4627Seric putc('?', f); 463*4627Seric for (o = OptList; o->opt_name != '\0'; o++) 464*4627Seric { 465*4627Seric if ((o->opt_value & flags) == o->opt_value) 466*4627Seric { 467*4627Seric flags &= ~o->opt_value; 468*4627Seric putc(o->opt_name, f); 469*4627Seric } 470*4627Seric } 471*4627Seric putc('?', f); 472*4627Seric } 473