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