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