1 # include "sendmail.h" 2 3 SCCSID(@(#)readcf.c 3.28 08/23/82); 4 5 /* 6 ** READCF -- read control file. 7 ** 8 ** This routine reads the control file and builds the internal 9 ** form. 10 ** 11 ** The file is formatted as a sequence of lines, each taken 12 ** atomically. The first character of each line describes how 13 ** the line is to be interpreted. The lines are: 14 ** Dxval Define macro x to have value val. 15 ** Cxword Put word into class x. 16 ** Fxfile [fmt] Read file for lines to put into 17 ** class x. Use scanf string 'fmt' 18 ** or "%s" if not present. Fmt should 19 ** only produce one string-valued result. 20 ** Hname: value Define header with field-name 'name' 21 ** and value as specified; this will be 22 ** macro expanded immediately before 23 ** use. 24 ** Sn Use rewriting set n. 25 ** Rlhs rhs Rewrite addresses that match lhs to 26 ** be rhs. 27 ** Mn p f r a Define mailer. n - internal name, 28 ** p - pathname, f - flags, r - rewriting 29 ** rule for sender, a - argument vector. 30 ** 31 ** Parameters: 32 ** cfname -- control file name. 33 ** safe -- set if this is a system configuration file. 34 ** Non-system configuration files can not do 35 ** certain things (e.g., leave the SUID bit on 36 ** when executing mailers). 37 ** 38 ** Returns: 39 ** none. 40 ** 41 ** Side Effects: 42 ** Builds several internal tables. 43 */ 44 45 struct rewrite *RewriteRules[10]; 46 47 48 readcf(cfname, safe) 49 char *cfname; 50 bool safe; 51 { 52 FILE *cf; 53 char buf[MAXLINE]; 54 register char *p; 55 struct rewrite *rwp = NULL; 56 extern char **prescan(); 57 extern char **copyplist(); 58 int class; 59 int ruleset = 0; 60 char exbuf[MAXLINE]; 61 char *q; 62 63 cf = fopen(cfname, "r"); 64 if (cf == NULL) 65 { 66 syserr("cannot open %s", cfname); 67 exit(EX_OSFILE); 68 } 69 70 while (fgetfolded(buf, sizeof buf, cf) != NULL) 71 { 72 switch (buf[0]) 73 { 74 case '\0': 75 case '#': /* comment */ 76 break; 77 78 case 'R': /* rewriting rule */ 79 for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 80 continue; 81 82 if (*p == '\0') 83 { 84 syserr("invalid rewrite line \"%s\"", buf); 85 break; 86 } 87 88 /* allocate space for the rule header */ 89 if (rwp == NULL) 90 { 91 RewriteRules[ruleset] = rwp = 92 (struct rewrite *) xalloc(sizeof *rwp); 93 } 94 else 95 { 96 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 97 rwp = rwp->r_next; 98 } 99 rwp->r_next = NULL; 100 101 /* expand and save the LHS */ 102 *p = '\0'; 103 expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv); 104 rwp->r_lhs = prescan(exbuf, '\t'); 105 if (rwp->r_lhs != NULL) 106 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 107 108 /* expand and save the RHS */ 109 while (*++p == '\t') 110 continue; 111 q = p; 112 while (*p != '\0' && *p != '\t') 113 p++; 114 *p = '\0'; 115 expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv); 116 rwp->r_rhs = prescan(exbuf, '\t'); 117 if (rwp->r_rhs != NULL) 118 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 119 break; 120 121 case 'S': /* select rewriting set */ 122 ruleset = atoi(&buf[1]); 123 rwp = NULL; 124 break; 125 126 case 'D': /* macro definition */ 127 define(buf[1], newstr(&buf[2])); 128 break; 129 130 case 'H': /* required header line */ 131 (void) chompheader(&buf[1], TRUE); 132 break; 133 134 case 'C': /* word class */ 135 case 'F': /* word class from file */ 136 class = buf[1]; 137 if (!isalpha(class)) 138 goto badline; 139 if (isupper(class)) 140 class -= 'A'; 141 else 142 class -= 'a'; 143 144 /* read list of words from argument or file */ 145 if (buf[0] == 'F') 146 { 147 /* read from file */ 148 for (p = &buf[2]; *p != '\0' && !isspace(*p); p++) 149 continue; 150 if (*p == '\0') 151 p = "%s"; 152 else 153 { 154 *p = '\0'; 155 while (isspace(*++p)) 156 continue; 157 } 158 fileclass(class, &buf[2], p); 159 break; 160 } 161 162 /* scan the list of words and set class for all */ 163 for (p = &buf[2]; *p != '\0'; ) 164 { 165 register char *wd; 166 char delim; 167 register STAB *s; 168 169 while (*p != '\0' && isspace(*p)) 170 p++; 171 wd = p; 172 while (*p != '\0' && !isspace(*p)) 173 p++; 174 delim = *p; 175 *p = '\0'; 176 if (wd[0] != '\0') 177 { 178 s = stab(wd, ST_CLASS, ST_ENTER); 179 s->s_class |= 1L << class; 180 } 181 *p = delim; 182 } 183 break; 184 185 case 'M': /* define mailer */ 186 makemailer(&buf[1], safe); 187 break; 188 189 default: 190 badline: 191 syserr("unknown control line \"%s\"", buf); 192 } 193 } 194 } 195 /* 196 ** FILECLASS -- read members of a class from a file 197 ** 198 ** Parameters: 199 ** class -- class to define. 200 ** filename -- name of file to read. 201 ** fmt -- scanf string to use for match. 202 ** 203 ** Returns: 204 ** none 205 ** 206 ** Side Effects: 207 ** 208 ** puts all lines in filename that match a scanf into 209 ** the named class. 210 */ 211 212 fileclass(class, filename, fmt) 213 int class; 214 char *filename; 215 char *fmt; 216 { 217 register FILE *f; 218 char buf[MAXLINE]; 219 220 f = fopen(filename, "r"); 221 if (f == NULL) 222 { 223 syserr("cannot open %s", filename); 224 return; 225 } 226 227 while (fgets(buf, sizeof buf, f) != NULL) 228 { 229 register STAB *s; 230 char wordbuf[MAXNAME+1]; 231 232 if (sscanf(buf, fmt, wordbuf) != 1) 233 continue; 234 s = stab(wordbuf, ST_CLASS, ST_ENTER); 235 s->s_class |= 1L << class; 236 } 237 238 (void) fclose(f); 239 } 240 /* 241 ** MAKEMAILER -- define a new mailer. 242 ** 243 ** Parameters: 244 ** line -- description of mailer. This is in tokens 245 ** separated by white space. The fields are: 246 ** * the name of the mailer, as refered to 247 ** in the rewriting rules. 248 ** * the pathname of the program to fork to 249 ** execute it. 250 ** * the options needed by this program. 251 ** * the macro string needed to translate 252 ** a local "from" name to one that can be 253 ** returned to this machine. 254 ** * the argument vector (a series of parameters). 255 ** safe -- set if this is a safe configuration file. 256 ** 257 ** Returns: 258 ** none. 259 ** 260 ** Side Effects: 261 ** enters the mailer into the mailer table. 262 */ 263 264 # define SETWORD \ 265 { \ 266 while (*p != '\0' && isspace(*p)) \ 267 p++; \ 268 q = p; \ 269 while (*p != '\0' && !isspace(*p)) \ 270 p++; \ 271 if (*p != '\0') \ 272 *p++ = '\0'; \ 273 } 274 275 makemailer(line, safe) 276 char *line; 277 bool safe; 278 { 279 register char *p; 280 register char *q; 281 char *mname; 282 char *mpath; 283 u_long mopts; 284 extern u_long mfencode(); 285 char *mfrom; 286 register struct mailer *m; 287 char *margv[MAXPV + 1]; 288 register int i; 289 extern int NextMailer; 290 STAB *s; 291 292 if (NextMailer >= MAXMAILERS) 293 { 294 syserr("Too many mailers defined"); 295 return; 296 } 297 298 /* collect initial information */ 299 p = line; 300 SETWORD; 301 mname = q; 302 SETWORD; 303 mpath = q; 304 SETWORD; 305 mopts = mfencode(q); 306 if (!safe) 307 mopts &= ~M_RESTR; 308 SETWORD; 309 mfrom = q; 310 311 if (*p == '\0') 312 { 313 syserr("invalid M line in configuration file"); 314 return; 315 } 316 317 /* allocate a mailer */ 318 m = (struct mailer *) xalloc(sizeof *m); 319 m->m_name = newstr(mname); 320 m->m_mailer = newstr(mpath); 321 m->m_flags = mopts; 322 m->m_from = newstr(mfrom); 323 m->m_badstat = EX_UNAVAILABLE; 324 m->m_mno = NextMailer; 325 Mailer[NextMailer++] = m; 326 327 /* collect the argument vector */ 328 for (i = 0; i < MAXPV - 1 && *p != '\0'; i++) 329 { 330 SETWORD; 331 margv[i] = newstr(q); 332 } 333 margv[i++] = NULL; 334 335 /* save the argv */ 336 m->m_argv = (char **) xalloc(sizeof margv[0] * i); 337 bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i); 338 s = stab(m->m_name, ST_MAILER, ST_ENTER); 339 s->s_mailer = m; 340 } 341 /* 342 ** PRINTRULES -- print rewrite rules (for debugging) 343 ** 344 ** Parameters: 345 ** none. 346 ** 347 ** Returns: 348 ** none. 349 ** 350 ** Side Effects: 351 ** prints rewrite rules. 352 */ 353 354 # ifdef DEBUG 355 356 printrules() 357 { 358 register struct rewrite *rwp; 359 register int ruleset; 360 361 for (ruleset = 0; ruleset < 10; ruleset++) 362 { 363 if (RewriteRules[ruleset] == NULL) 364 continue; 365 printf("\n----Rule Set %d:\n", ruleset); 366 367 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 368 { 369 register char **av; 370 371 printf("\n"); 372 for (av = rwp->r_lhs; *av != NULL; av++) 373 { 374 xputs(*av); 375 putchar('_'); 376 } 377 printf("\n\t"); 378 for (av = rwp->r_rhs; *av != NULL; av++) 379 { 380 xputs(*av); 381 putchar('_'); 382 } 383 printf("\n"); 384 } 385 } 386 } 387 388 # endif DEBUG 389 /* 390 ** MFENCODE -- crack mailer options 391 ** 392 ** These options modify the functioning of the mailer 393 ** from the configuration table. 394 ** 395 ** Parameters: 396 ** p -- pointer to vector of options. 397 ** 398 ** Returns: 399 ** option list in binary. 400 ** 401 ** Side Effects: 402 ** none. 403 */ 404 405 struct optlist 406 { 407 char opt_name; /* external name of option */ 408 u_long opt_value; /* internal name of option */ 409 }; 410 struct optlist OptList[] = 411 { 412 'f', M_FOPT, 413 'r', M_ROPT, 414 'q', M_QUIET, 415 'S', M_RESTR, 416 'n', M_NHDR, 417 'l', M_LOCAL, 418 's', M_STRIPQ, 419 'm', M_MUSER, 420 'F', M_NEEDFROM, 421 'D', M_NEEDDATE, 422 'M', M_MSGID, 423 'u', M_USR_UPPER, 424 'h', M_HST_UPPER, 425 'x', M_FULLNAME, 426 'A', M_ARPAFMT, 427 'U', M_UGLYUUCP, 428 'e', M_EXPENSIVE, 429 'R', M_RELRCPT, 430 'X', M_FULLSMTP, 431 '\0', 0 432 }; 433 434 u_long 435 mfencode(p) 436 register char *p; 437 { 438 register struct optlist *o; 439 register u_long opts = 0; 440 441 while (*p != '\0') 442 { 443 for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++) 444 continue; 445 if (o->opt_name == '\0') 446 syserr("bad mailer option %c", *p); 447 opts |= o->opt_value; 448 p++; 449 } 450 return (opts); 451 } 452 /* 453 ** MFDECODE -- decode mailer flags into external form. 454 ** 455 ** Parameters: 456 ** flags -- value of flags to decode. 457 ** f -- file to write them onto. 458 ** 459 ** Returns: 460 ** none. 461 ** 462 ** Side Effects: 463 ** none. 464 */ 465 466 mfdecode(flags, f) 467 u_long flags; 468 FILE *f; 469 { 470 register struct optlist *o; 471 472 putc('?', f); 473 for (o = OptList; o->opt_name != '\0'; o++) 474 { 475 if ((o->opt_value & flags) == o->opt_value) 476 { 477 flags &= ~o->opt_value; 478 putc(o->opt_name, f); 479 } 480 } 481 putc('?', f); 482 } 483