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