1 # include "sendmail.h" 2 3 static char SccsId[] = "@(#)readcf.c 3.14 09/23/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 283 if (NextMailer >= MAXMAILERS) 284 { 285 syserr("Too many mailers defined"); 286 return; 287 } 288 289 /* collect initial information */ 290 p = line; 291 SETWORD; 292 mname = q; 293 SETWORD; 294 mpath = q; 295 SETWORD; 296 mopts = crackopts(q); 297 if (!safe) 298 mopts &= ~M_RESTR; 299 SETWORD; 300 mfrom = q; 301 302 if (*p == '\0') 303 { 304 syserr("invalid M line in configuration file"); 305 return; 306 } 307 308 /* allocate a mailer */ 309 m = (struct mailer *) xalloc(sizeof *m); 310 m->m_name = newstr(mname); 311 m->m_mailer = newstr(mpath); 312 m->m_flags = mopts; 313 m->m_from = newstr(mfrom); 314 m->m_badstat = EX_UNAVAILABLE; 315 m->m_sendq = NULL; 316 Mailer[NextMailer++] = m; 317 318 /* collect the argument vector */ 319 for (i = 0; i < MAXPV - 1 && *p != '\0'; i++) 320 { 321 SETWORD; 322 margv[i] = newstr(q); 323 } 324 margv[i++] = NULL; 325 326 /* save the argv */ 327 m->m_argv = (char **) xalloc((unsigned) (sizeof margv[0] * i)); 328 bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i); 329 } 330 /* 331 ** PRINTRULES -- print rewrite rules (for debugging) 332 ** 333 ** Parameters: 334 ** none. 335 ** 336 ** Returns: 337 ** none. 338 ** 339 ** Side Effects: 340 ** prints rewrite rules. 341 */ 342 343 # ifdef DEBUG 344 345 printrules() 346 { 347 register struct rewrite *rwp; 348 register int ruleset; 349 350 for (ruleset = 0; ruleset < 10; ruleset++) 351 { 352 if (RewriteRules[ruleset] == NULL) 353 continue; 354 printf("\n----Rule Set %d:\n", ruleset); 355 356 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 357 { 358 register char **av; 359 360 printf("\n"); 361 for (av = rwp->r_lhs; *av != NULL; av++) 362 { 363 xputs(*av); 364 putchar('_'); 365 } 366 printf("\n\t"); 367 for (av = rwp->r_rhs; *av != NULL; av++) 368 { 369 xputs(*av); 370 putchar('_'); 371 } 372 printf("\n"); 373 } 374 } 375 } 376 377 # endif DEBUG 378 /* 379 ** CRACKOPTS -- crack mailer options 380 ** 381 ** These options modify the functioning of the mailer 382 ** from the configuration table. 383 ** 384 ** Parameters: 385 ** p -- pointer to vector of options. 386 ** 387 ** Returns: 388 ** option list in binary. 389 ** 390 ** Side Effects: 391 ** none. 392 */ 393 394 struct optlist 395 { 396 char opt_name; /* external name of option */ 397 int opt_value; /* internal name of option */ 398 }; 399 struct optlist OptList[] = 400 { 401 'f', M_FOPT, 402 'r', M_ROPT, 403 'q', M_QUIET, 404 'S', M_RESTR, 405 'n', M_NHDR, 406 'l', M_LOCAL, 407 's', M_STRIPQ, 408 'm', M_MUSER, 409 'F', M_NEEDFROM, 410 'D', M_NEEDDATE, 411 'M', M_MSGID, 412 'u', M_USR_UPPER, 413 'h', M_HST_UPPER, 414 'x', M_FULLNAME, 415 'A', M_ARPAFMT, 416 '\0', 0 417 }; 418 419 crackopts(p) 420 register char *p; 421 { 422 register struct optlist *o; 423 register int opts = 0; 424 425 while (*p != '\0') 426 { 427 for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++) 428 continue; 429 if (o->opt_name == '\0') 430 syserr("bad mailer option %c", *p); 431 opts |= o->opt_value; 432 p++; 433 } 434 return (opts); 435 } 436