1 # include "sendmail.h" 2 3 static char SccsId[] = "@(#)readcf.c 3.13 09/06/81"; 4 5 /* 6 ** READCF -- read control file. 7 ** 8 ** This routine reads the control file and builds the internal 9 ** form. 10 ** 11 ** Parameters: 12 ** cfname -- control file name. 13 ** safe -- set if this is a system configuration file. 14 ** Non-system configuration files can not do 15 ** certain things (e.g., leave the SUID bit on 16 ** when executing mailers). 17 ** 18 ** Returns: 19 ** none. 20 ** 21 ** Side Effects: 22 ** Builds several internal tables. 23 */ 24 25 struct rewrite *RewriteRules[10]; 26 27 28 readcf(cfname, safe) 29 char *cfname; 30 bool safe; 31 { 32 FILE *cf; 33 char buf[MAXLINE]; 34 register char *p; 35 struct rewrite *rwp = NULL; 36 extern char **prescan(); 37 extern char **copyplist(); 38 int class; 39 int ruleset = 0; 40 41 cf = fopen(cfname, "r"); 42 if (cf == NULL) 43 { 44 syserr("cannot open %s", cfname); 45 exit(EX_OSFILE); 46 } 47 48 while (fgets(buf, sizeof buf, cf) != NULL) 49 { 50 p = rindex(buf, '\n'); 51 if (p != NULL) 52 *p = '\0'; 53 54 switch (buf[0]) 55 { 56 case '\n': 57 case '\0': 58 case ' ': 59 case '\t': 60 case '#': /* comment */ 61 break; 62 63 case 'R': /* rewriting rule */ 64 for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) 65 continue; 66 67 if (*p == '\0') 68 syserr("invalid rewrite line \"%s\"", buf); 69 else 70 { 71 if (rwp == NULL) 72 { 73 RewriteRules[ruleset] = rwp = 74 (struct rewrite *) xalloc(sizeof *rwp); 75 } 76 else 77 { 78 rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 79 rwp = rwp->r_next; 80 } 81 rwp->r_next = NULL; 82 83 rwp->r_lhs = prescan(&buf[1], '\t'); 84 if (rwp->r_lhs != NULL) 85 rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 86 while (*p == '\t') 87 p++; 88 rwp->r_rhs = prescan(p, '\t'); 89 if (rwp->r_rhs != NULL) 90 rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 91 } 92 break; 93 94 case 'S': /* select rewriting set */ 95 ruleset = atoi(&buf[1]); 96 rwp = NULL; 97 break; 98 99 case 'D': /* macro definition */ 100 define(buf[1], newstr(&buf[2])); 101 break; 102 103 case 'H': /* required header line */ 104 (void) chompheader(&buf[1], TRUE); 105 break; 106 107 case 'C': /* word class */ 108 class = buf[1]; 109 if (!isalpha(class)) 110 goto badline; 111 if (isupper(class)) 112 class -= 'A'; 113 else 114 class -= 'a'; 115 116 /* scan the list of words and set class 'i' for all */ 117 for (p = &buf[2]; *p != '\0'; ) 118 { 119 register char *wd; 120 char delim; 121 register STAB *s; 122 123 while (*p != '\0' && isspace(*p)) 124 p++; 125 wd = p; 126 while (*p != '\0' && !isspace(*p)) 127 p++; 128 delim = *p; 129 *p = '\0'; 130 if (wd[0] != '\0') 131 { 132 s = stab(wd, ST_CLASS, ST_ENTER); 133 s->s_class |= 1 << class; 134 } 135 *p = delim; 136 } 137 break; 138 139 case 'M': /* define mailer */ 140 makemailer(&buf[1], safe); 141 break; 142 143 default: 144 badline: 145 syserr("unknown control line \"%s\"", buf); 146 } 147 } 148 } 149 /* 150 ** MAKEMAILER -- define a new mailer. 151 ** 152 ** Parameters: 153 ** line -- description of mailer. This is in tokens 154 ** separated by white space. The fields are: 155 ** * the name of the mailer, as refered to 156 ** in the rewriting rules. 157 ** * the pathname of the program to fork to 158 ** execute it. 159 ** * the options needed by this program. 160 ** * the macro string needed to translate 161 ** a local "from" name to one that can be 162 ** returned to this machine. 163 ** * the argument vector (a series of parameters). 164 ** safe -- set if this is a safe configuration file. 165 ** 166 ** Returns: 167 ** none. 168 ** 169 ** Side Effects: 170 ** enters the mailer into the mailer table. 171 */ 172 173 # define SETWORD \ 174 { \ 175 while (*p != '\0' && isspace(*p)) \ 176 p++; \ 177 q = p; \ 178 while (*p != '\0' && !isspace(*p)) \ 179 p++; \ 180 if (*p != '\0') \ 181 *p++ = '\0'; \ 182 } 183 184 makemailer(line, safe) 185 char *line; 186 bool safe; 187 { 188 register char *p; 189 register char *q; 190 char *mname; 191 char *mpath; 192 int mopts; 193 char *mfrom; 194 register struct mailer *m; 195 char *margv[MAXPV + 1]; 196 register int i; 197 extern int NextMailer; 198 199 if (NextMailer >= MAXMAILERS) 200 { 201 syserr("Too many mailers defined"); 202 return; 203 } 204 205 /* collect initial information */ 206 p = line; 207 SETWORD; 208 mname = q; 209 SETWORD; 210 mpath = q; 211 SETWORD; 212 mopts = crackopts(q); 213 if (!safe) 214 mopts &= ~M_RESTR; 215 SETWORD; 216 mfrom = q; 217 218 if (*p == '\0') 219 { 220 syserr("invalid M line in configuration file"); 221 return; 222 } 223 224 /* allocate a mailer */ 225 m = (struct mailer *) xalloc(sizeof *m); 226 m->m_name = newstr(mname); 227 m->m_mailer = newstr(mpath); 228 m->m_flags = mopts; 229 m->m_from = newstr(mfrom); 230 m->m_badstat = EX_UNAVAILABLE; 231 m->m_sendq = NULL; 232 Mailer[NextMailer++] = m; 233 234 /* collect the argument vector */ 235 for (i = 0; i < MAXPV - 1 && *p != '\0'; i++) 236 { 237 SETWORD; 238 margv[i] = newstr(q); 239 } 240 margv[i++] = NULL; 241 242 /* save the argv */ 243 m->m_argv = (char **) xalloc((unsigned) (sizeof margv[0] * i)); 244 bmove((char *) margv, (char *) m->m_argv, sizeof margv[0] * i); 245 } 246 /* 247 ** PRINTRULES -- print rewrite rules (for debugging) 248 ** 249 ** Parameters: 250 ** none. 251 ** 252 ** Returns: 253 ** none. 254 ** 255 ** Side Effects: 256 ** prints rewrite rules. 257 */ 258 259 # ifdef DEBUG 260 261 printrules() 262 { 263 register struct rewrite *rwp; 264 register int ruleset; 265 266 for (ruleset = 0; ruleset < 10; ruleset++) 267 { 268 if (RewriteRules[ruleset] == NULL) 269 continue; 270 printf("\n----Rule Set %d:\n", ruleset); 271 272 for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 273 { 274 register char **av; 275 276 printf("\n"); 277 for (av = rwp->r_lhs; *av != NULL; av++) 278 { 279 xputs(*av); 280 putchar('_'); 281 } 282 printf("\n\t"); 283 for (av = rwp->r_rhs; *av != NULL; av++) 284 { 285 xputs(*av); 286 putchar('_'); 287 } 288 printf("\n"); 289 } 290 } 291 } 292 293 # endif DEBUG 294 /* 295 ** CRACKOPTS -- crack mailer options 296 ** 297 ** These options modify the functioning of the mailer 298 ** from the configuration table. 299 ** 300 ** Parameters: 301 ** p -- pointer to vector of options. 302 ** 303 ** Returns: 304 ** option list in binary. 305 ** 306 ** Side Effects: 307 ** none. 308 */ 309 310 struct optlist 311 { 312 char opt_name; /* external name of option */ 313 int opt_value; /* internal name of option */ 314 }; 315 struct optlist OptList[] = 316 { 317 'f', M_FOPT, 318 'r', M_ROPT, 319 'q', M_QUIET, 320 'S', M_RESTR, 321 'n', M_NHDR, 322 'l', M_LOCAL, 323 's', M_STRIPQ, 324 'm', M_MUSER, 325 'F', M_NEEDFROM, 326 'D', M_NEEDDATE, 327 'M', M_MSGID, 328 'u', M_USR_UPPER, 329 'h', M_HST_UPPER, 330 'x', M_FULLNAME, 331 'A', M_ARPAFMT, 332 '\0', 0 333 }; 334 335 crackopts(p) 336 register char *p; 337 { 338 register struct optlist *o; 339 register int opts = 0; 340 341 while (*p != '\0') 342 { 343 for (o = OptList; o->opt_name != '\0' && o->opt_name != *p; o++) 344 continue; 345 if (o->opt_name == '\0') 346 syserr("bad mailer option %c", *p); 347 opts |= o->opt_value; 348 p++; 349 } 350 return (opts); 351 } 352