1 | /* |
---|
2 | * Copyright (c) 1998 Sendmail, Inc. All rights reserved. |
---|
3 | * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. |
---|
4 | * Copyright (c) 1988, 1993 |
---|
5 | * The Regents of the University of California. All rights reserved. |
---|
6 | * |
---|
7 | * By using this file, you agree to the terms and conditions set |
---|
8 | * forth in the LICENSE file which can be found at the top level of |
---|
9 | * the sendmail distribution. |
---|
10 | * |
---|
11 | */ |
---|
12 | |
---|
13 | #ifndef lint |
---|
14 | static char sccsid[] = "@(#)readcf.c 8.238 (Berkeley) 1/28/1999"; |
---|
15 | #endif /* not lint */ |
---|
16 | |
---|
17 | # include "sendmail.h" |
---|
18 | # include <grp.h> |
---|
19 | #if NAMED_BIND |
---|
20 | # include <resolv.h> |
---|
21 | #endif |
---|
22 | |
---|
23 | /* |
---|
24 | ** READCF -- read configuration file. |
---|
25 | ** |
---|
26 | ** This routine reads the configuration file and builds the internal |
---|
27 | ** form. |
---|
28 | ** |
---|
29 | ** The file is formatted as a sequence of lines, each taken |
---|
30 | ** atomically. The first character of each line describes how |
---|
31 | ** the line is to be interpreted. The lines are: |
---|
32 | ** Dxval Define macro x to have value val. |
---|
33 | ** Cxword Put word into class x. |
---|
34 | ** Fxfile [fmt] Read file for lines to put into |
---|
35 | ** class x. Use scanf string 'fmt' |
---|
36 | ** or "%s" if not present. Fmt should |
---|
37 | ** only produce one string-valued result. |
---|
38 | ** Hname: value Define header with field-name 'name' |
---|
39 | ** and value as specified; this will be |
---|
40 | ** macro expanded immediately before |
---|
41 | ** use. |
---|
42 | ** Sn Use rewriting set n. |
---|
43 | ** Rlhs rhs Rewrite addresses that match lhs to |
---|
44 | ** be rhs. |
---|
45 | ** Mn arg=val... Define mailer. n is the internal name. |
---|
46 | ** Args specify mailer parameters. |
---|
47 | ** Oxvalue Set option x to value. |
---|
48 | ** Pname=value Set precedence name to value. |
---|
49 | ** Vversioncode[/vendorcode] |
---|
50 | ** Version level/vendor name of |
---|
51 | ** configuration syntax. |
---|
52 | ** Kmapname mapclass arguments.... |
---|
53 | ** Define keyed lookup of a given class. |
---|
54 | ** Arguments are class dependent. |
---|
55 | ** Eenvar=value Set the environment value to the given value. |
---|
56 | ** |
---|
57 | ** Parameters: |
---|
58 | ** cfname -- configuration file name. |
---|
59 | ** safe -- TRUE if this is the system config file; |
---|
60 | ** FALSE otherwise. |
---|
61 | ** e -- the main envelope. |
---|
62 | ** |
---|
63 | ** Returns: |
---|
64 | ** none. |
---|
65 | ** |
---|
66 | ** Side Effects: |
---|
67 | ** Builds several internal tables. |
---|
68 | */ |
---|
69 | |
---|
70 | void |
---|
71 | readcf(cfname, safe, e) |
---|
72 | char *cfname; |
---|
73 | bool safe; |
---|
74 | register ENVELOPE *e; |
---|
75 | { |
---|
76 | FILE *cf; |
---|
77 | int ruleset = 0; |
---|
78 | char *q; |
---|
79 | struct rewrite *rwp = NULL; |
---|
80 | char *bp; |
---|
81 | auto char *ep; |
---|
82 | int nfuzzy; |
---|
83 | char *file; |
---|
84 | bool optional; |
---|
85 | int mid; |
---|
86 | register char *p; |
---|
87 | int sff = SFF_OPENASROOT; |
---|
88 | struct stat statb; |
---|
89 | char buf[MAXLINE]; |
---|
90 | char exbuf[MAXLINE]; |
---|
91 | char pvpbuf[MAXLINE + MAXATOM]; |
---|
92 | static char *null_list[1] = { NULL }; |
---|
93 | extern char **copyplist __P((char **, bool)); |
---|
94 | extern char *munchstring __P((char *, char **, int)); |
---|
95 | extern void fileclass __P((int, char *, char *, bool, bool)); |
---|
96 | extern void toomany __P((int, int)); |
---|
97 | extern void translate_dollars __P((char *)); |
---|
98 | extern void inithostmaps __P((void)); |
---|
99 | |
---|
100 | FileName = cfname; |
---|
101 | LineNumber = 0; |
---|
102 | |
---|
103 | if (DontLockReadFiles) |
---|
104 | sff |= SFF_NOLOCK; |
---|
105 | cf = safefopen(cfname, O_RDONLY, 0444, sff); |
---|
106 | if (cf == NULL) |
---|
107 | { |
---|
108 | syserr("cannot open"); |
---|
109 | finis(FALSE, EX_OSFILE); |
---|
110 | } |
---|
111 | |
---|
112 | if (fstat(fileno(cf), &statb) < 0) |
---|
113 | { |
---|
114 | syserr("cannot fstat"); |
---|
115 | finis(FALSE, EX_OSFILE); |
---|
116 | } |
---|
117 | |
---|
118 | if (!S_ISREG(statb.st_mode)) |
---|
119 | { |
---|
120 | syserr("not a plain file"); |
---|
121 | finis(FALSE, EX_OSFILE); |
---|
122 | } |
---|
123 | |
---|
124 | if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) |
---|
125 | { |
---|
126 | if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) |
---|
127 | fprintf(stderr, "%s: WARNING: dangerous write permissions\n", |
---|
128 | FileName); |
---|
129 | if (LogLevel > 0) |
---|
130 | sm_syslog(LOG_CRIT, NOQID, |
---|
131 | "%s: WARNING: dangerous write permissions", |
---|
132 | FileName); |
---|
133 | } |
---|
134 | |
---|
135 | #ifdef XLA |
---|
136 | xla_zero(); |
---|
137 | #endif |
---|
138 | |
---|
139 | while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) |
---|
140 | { |
---|
141 | if (bp[0] == '#') |
---|
142 | { |
---|
143 | if (bp != buf) |
---|
144 | free(bp); |
---|
145 | continue; |
---|
146 | } |
---|
147 | |
---|
148 | /* do macro expansion mappings */ |
---|
149 | translate_dollars(bp); |
---|
150 | |
---|
151 | /* interpret this line */ |
---|
152 | errno = 0; |
---|
153 | switch (bp[0]) |
---|
154 | { |
---|
155 | case '\0': |
---|
156 | case '#': /* comment */ |
---|
157 | break; |
---|
158 | |
---|
159 | case 'R': /* rewriting rule */ |
---|
160 | for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) |
---|
161 | continue; |
---|
162 | |
---|
163 | if (*p == '\0') |
---|
164 | { |
---|
165 | syserr("invalid rewrite line \"%s\" (tab expected)", bp); |
---|
166 | break; |
---|
167 | } |
---|
168 | |
---|
169 | /* allocate space for the rule header */ |
---|
170 | if (rwp == NULL) |
---|
171 | { |
---|
172 | RewriteRules[ruleset] = rwp = |
---|
173 | (struct rewrite *) xalloc(sizeof *rwp); |
---|
174 | } |
---|
175 | else |
---|
176 | { |
---|
177 | rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); |
---|
178 | rwp = rwp->r_next; |
---|
179 | } |
---|
180 | rwp->r_next = NULL; |
---|
181 | |
---|
182 | /* expand and save the LHS */ |
---|
183 | *p = '\0'; |
---|
184 | expand(&bp[1], exbuf, sizeof exbuf, e); |
---|
185 | rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, |
---|
186 | sizeof pvpbuf, NULL, NULL); |
---|
187 | nfuzzy = 0; |
---|
188 | if (rwp->r_lhs != NULL) |
---|
189 | { |
---|
190 | register char **ap; |
---|
191 | |
---|
192 | rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); |
---|
193 | |
---|
194 | /* count the number of fuzzy matches in LHS */ |
---|
195 | for (ap = rwp->r_lhs; *ap != NULL; ap++) |
---|
196 | { |
---|
197 | char *botch; |
---|
198 | |
---|
199 | botch = NULL; |
---|
200 | switch (**ap & 0377) |
---|
201 | { |
---|
202 | case MATCHZANY: |
---|
203 | case MATCHANY: |
---|
204 | case MATCHONE: |
---|
205 | case MATCHCLASS: |
---|
206 | case MATCHNCLASS: |
---|
207 | nfuzzy++; |
---|
208 | break; |
---|
209 | |
---|
210 | case MATCHREPL: |
---|
211 | botch = "$0-$9"; |
---|
212 | break; |
---|
213 | |
---|
214 | case CANONUSER: |
---|
215 | botch = "$:"; |
---|
216 | break; |
---|
217 | |
---|
218 | case CALLSUBR: |
---|
219 | botch = "$>"; |
---|
220 | break; |
---|
221 | |
---|
222 | case CONDIF: |
---|
223 | botch = "$?"; |
---|
224 | break; |
---|
225 | |
---|
226 | case CONDFI: |
---|
227 | botch = "$."; |
---|
228 | break; |
---|
229 | |
---|
230 | case HOSTBEGIN: |
---|
231 | botch = "$["; |
---|
232 | break; |
---|
233 | |
---|
234 | case HOSTEND: |
---|
235 | botch = "$]"; |
---|
236 | break; |
---|
237 | |
---|
238 | case LOOKUPBEGIN: |
---|
239 | botch = "$("; |
---|
240 | break; |
---|
241 | |
---|
242 | case LOOKUPEND: |
---|
243 | botch = "$)"; |
---|
244 | break; |
---|
245 | } |
---|
246 | if (botch != NULL) |
---|
247 | syserr("Inappropriate use of %s on LHS", |
---|
248 | botch); |
---|
249 | } |
---|
250 | } |
---|
251 | else |
---|
252 | { |
---|
253 | syserr("R line: null LHS"); |
---|
254 | rwp->r_lhs = null_list; |
---|
255 | } |
---|
256 | |
---|
257 | /* expand and save the RHS */ |
---|
258 | while (*++p == '\t') |
---|
259 | continue; |
---|
260 | q = p; |
---|
261 | while (*p != '\0' && *p != '\t') |
---|
262 | p++; |
---|
263 | *p = '\0'; |
---|
264 | expand(q, exbuf, sizeof exbuf, e); |
---|
265 | rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, |
---|
266 | sizeof pvpbuf, NULL, NULL); |
---|
267 | if (rwp->r_rhs != NULL) |
---|
268 | { |
---|
269 | register char **ap; |
---|
270 | |
---|
271 | rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); |
---|
272 | |
---|
273 | /* check no out-of-bounds replacements */ |
---|
274 | nfuzzy += '0'; |
---|
275 | for (ap = rwp->r_rhs; *ap != NULL; ap++) |
---|
276 | { |
---|
277 | char *botch; |
---|
278 | |
---|
279 | botch = NULL; |
---|
280 | switch (**ap & 0377) |
---|
281 | { |
---|
282 | case MATCHREPL: |
---|
283 | if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) |
---|
284 | { |
---|
285 | syserr("replacement $%c out of bounds", |
---|
286 | (*ap)[1]); |
---|
287 | } |
---|
288 | break; |
---|
289 | |
---|
290 | case MATCHZANY: |
---|
291 | botch = "$*"; |
---|
292 | break; |
---|
293 | |
---|
294 | case MATCHANY: |
---|
295 | botch = "$+"; |
---|
296 | break; |
---|
297 | |
---|
298 | case MATCHONE: |
---|
299 | botch = "$-"; |
---|
300 | break; |
---|
301 | |
---|
302 | case MATCHCLASS: |
---|
303 | botch = "$="; |
---|
304 | break; |
---|
305 | |
---|
306 | case MATCHNCLASS: |
---|
307 | botch = "$~"; |
---|
308 | break; |
---|
309 | } |
---|
310 | if (botch != NULL) |
---|
311 | syserr("Inappropriate use of %s on RHS", |
---|
312 | botch); |
---|
313 | } |
---|
314 | } |
---|
315 | else |
---|
316 | { |
---|
317 | syserr("R line: null RHS"); |
---|
318 | rwp->r_rhs = null_list; |
---|
319 | } |
---|
320 | break; |
---|
321 | |
---|
322 | case 'S': /* select rewriting set */ |
---|
323 | expand(&bp[1], exbuf, sizeof exbuf, e); |
---|
324 | ruleset = strtorwset(exbuf, NULL, ST_ENTER); |
---|
325 | if (ruleset < 0) |
---|
326 | break; |
---|
327 | rwp = RewriteRules[ruleset]; |
---|
328 | if (rwp != NULL) |
---|
329 | { |
---|
330 | if (OpMode == MD_TEST || tTd(37, 1)) |
---|
331 | printf("WARNING: Ruleset %s has multiple definitions\n", |
---|
332 | &bp[1]); |
---|
333 | while (rwp->r_next != NULL) |
---|
334 | rwp = rwp->r_next; |
---|
335 | } |
---|
336 | break; |
---|
337 | |
---|
338 | case 'D': /* macro definition */ |
---|
339 | mid = macid(&bp[1], &ep); |
---|
340 | p = munchstring(ep, NULL, '\0'); |
---|
341 | define(mid, newstr(p), e); |
---|
342 | break; |
---|
343 | |
---|
344 | case 'H': /* required header line */ |
---|
345 | (void) chompheader(&bp[1], TRUE, NULL, e); |
---|
346 | break; |
---|
347 | |
---|
348 | case 'C': /* word class */ |
---|
349 | case 'T': /* trusted user (set class `t') */ |
---|
350 | if (bp[0] == 'C') |
---|
351 | { |
---|
352 | mid = macid(&bp[1], &ep); |
---|
353 | expand(ep, exbuf, sizeof exbuf, e); |
---|
354 | p = exbuf; |
---|
355 | } |
---|
356 | else |
---|
357 | { |
---|
358 | mid = 't'; |
---|
359 | p = &bp[1]; |
---|
360 | } |
---|
361 | while (*p != '\0') |
---|
362 | { |
---|
363 | register char *wd; |
---|
364 | char delim; |
---|
365 | |
---|
366 | while (*p != '\0' && isascii(*p) && isspace(*p)) |
---|
367 | p++; |
---|
368 | wd = p; |
---|
369 | while (*p != '\0' && !(isascii(*p) && isspace(*p))) |
---|
370 | p++; |
---|
371 | delim = *p; |
---|
372 | *p = '\0'; |
---|
373 | if (wd[0] != '\0') |
---|
374 | setclass(mid, wd); |
---|
375 | *p = delim; |
---|
376 | } |
---|
377 | break; |
---|
378 | |
---|
379 | case 'F': /* word class from file */ |
---|
380 | mid = macid(&bp[1], &ep); |
---|
381 | for (p = ep; isascii(*p) && isspace(*p); ) |
---|
382 | p++; |
---|
383 | if (p[0] == '-' && p[1] == 'o') |
---|
384 | { |
---|
385 | optional = TRUE; |
---|
386 | while (*p != '\0' && !(isascii(*p) && isspace(*p))) |
---|
387 | p++; |
---|
388 | while (isascii(*p) && isspace(*p)) |
---|
389 | p++; |
---|
390 | } |
---|
391 | else |
---|
392 | optional = FALSE; |
---|
393 | file = p; |
---|
394 | if (*file == '|') |
---|
395 | p = "%s"; |
---|
396 | else |
---|
397 | { |
---|
398 | while (*p != '\0' && !(isascii(*p) && isspace(*p))) |
---|
399 | p++; |
---|
400 | if (*p == '\0') |
---|
401 | p = "%s"; |
---|
402 | else |
---|
403 | { |
---|
404 | *p = '\0'; |
---|
405 | while (isascii(*++p) && isspace(*p)) |
---|
406 | continue; |
---|
407 | } |
---|
408 | } |
---|
409 | fileclass(mid, file, p, safe, optional); |
---|
410 | break; |
---|
411 | |
---|
412 | #ifdef XLA |
---|
413 | case 'L': /* extended load average description */ |
---|
414 | xla_init(&bp[1]); |
---|
415 | break; |
---|
416 | #endif |
---|
417 | |
---|
418 | #if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) |
---|
419 | case 'L': /* lookup macro */ |
---|
420 | case 'G': /* lookup class */ |
---|
421 | /* reserved for Sun -- NIS+ database lookup */ |
---|
422 | if (VendorCode != VENDOR_SUN) |
---|
423 | goto badline; |
---|
424 | sun_lg_config_line(bp, e); |
---|
425 | break; |
---|
426 | #endif |
---|
427 | |
---|
428 | case 'M': /* define mailer */ |
---|
429 | makemailer(&bp[1]); |
---|
430 | break; |
---|
431 | |
---|
432 | case 'O': /* set option */ |
---|
433 | setoption(bp[1], &bp[2], safe, FALSE, e); |
---|
434 | break; |
---|
435 | |
---|
436 | case 'P': /* set precedence */ |
---|
437 | if (NumPriorities >= MAXPRIORITIES) |
---|
438 | { |
---|
439 | toomany('P', MAXPRIORITIES); |
---|
440 | break; |
---|
441 | } |
---|
442 | for (p = &bp[1]; *p != '\0' && *p != '='; p++) |
---|
443 | continue; |
---|
444 | if (*p == '\0') |
---|
445 | goto badline; |
---|
446 | *p = '\0'; |
---|
447 | Priorities[NumPriorities].pri_name = newstr(&bp[1]); |
---|
448 | Priorities[NumPriorities].pri_val = atoi(++p); |
---|
449 | NumPriorities++; |
---|
450 | break; |
---|
451 | |
---|
452 | case 'V': /* configuration syntax version */ |
---|
453 | for (p = &bp[1]; isascii(*p) && isspace(*p); p++) |
---|
454 | continue; |
---|
455 | if (!isascii(*p) || !isdigit(*p)) |
---|
456 | { |
---|
457 | syserr("invalid argument to V line: \"%.20s\"", |
---|
458 | &bp[1]); |
---|
459 | break; |
---|
460 | } |
---|
461 | ConfigLevel = strtol(p, &ep, 10); |
---|
462 | |
---|
463 | /* |
---|
464 | ** Do heuristic tweaking for back compatibility. |
---|
465 | */ |
---|
466 | |
---|
467 | if (ConfigLevel >= 5) |
---|
468 | { |
---|
469 | /* level 5 configs have short name in $w */ |
---|
470 | p = macvalue('w', e); |
---|
471 | if (p != NULL && (p = strchr(p, '.')) != NULL) |
---|
472 | *p = '\0'; |
---|
473 | define('w', macvalue('w', e), e); |
---|
474 | } |
---|
475 | if (ConfigLevel >= 6) |
---|
476 | { |
---|
477 | ColonOkInAddr = FALSE; |
---|
478 | } |
---|
479 | |
---|
480 | /* |
---|
481 | ** Look for vendor code. |
---|
482 | */ |
---|
483 | |
---|
484 | if (*ep++ == '/') |
---|
485 | { |
---|
486 | extern bool setvendor __P((char *)); |
---|
487 | |
---|
488 | /* extract vendor code */ |
---|
489 | for (p = ep; isascii(*p) && isalpha(*p); ) |
---|
490 | p++; |
---|
491 | *p = '\0'; |
---|
492 | |
---|
493 | if (!setvendor(ep)) |
---|
494 | syserr("invalid V line vendor code: \"%s\"", |
---|
495 | ep); |
---|
496 | } |
---|
497 | break; |
---|
498 | |
---|
499 | case 'K': |
---|
500 | expand(&bp[1], exbuf, sizeof exbuf, e); |
---|
501 | (void) makemapentry(exbuf); |
---|
502 | break; |
---|
503 | |
---|
504 | case 'E': |
---|
505 | p = strchr(bp, '='); |
---|
506 | if (p != NULL) |
---|
507 | *p++ = '\0'; |
---|
508 | setuserenv(&bp[1], p); |
---|
509 | break; |
---|
510 | |
---|
511 | default: |
---|
512 | badline: |
---|
513 | syserr("unknown configuration line \"%s\"", bp); |
---|
514 | } |
---|
515 | if (bp != buf) |
---|
516 | free(bp); |
---|
517 | } |
---|
518 | if (ferror(cf)) |
---|
519 | { |
---|
520 | syserr("I/O read error"); |
---|
521 | finis(FALSE, EX_OSFILE); |
---|
522 | } |
---|
523 | fclose(cf); |
---|
524 | FileName = NULL; |
---|
525 | |
---|
526 | /* initialize host maps from local service tables */ |
---|
527 | inithostmaps(); |
---|
528 | |
---|
529 | /* determine if we need to do special name-server frotz */ |
---|
530 | { |
---|
531 | int nmaps; |
---|
532 | char *maptype[MAXMAPSTACK]; |
---|
533 | short mapreturn[MAXMAPACTIONS]; |
---|
534 | |
---|
535 | nmaps = switch_map_find("hosts", maptype, mapreturn); |
---|
536 | UseNameServer = FALSE; |
---|
537 | if (nmaps > 0 && nmaps <= MAXMAPSTACK) |
---|
538 | { |
---|
539 | register int mapno; |
---|
540 | |
---|
541 | for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) |
---|
542 | { |
---|
543 | if (strcmp(maptype[mapno], "dns") == 0) |
---|
544 | UseNameServer = TRUE; |
---|
545 | } |
---|
546 | } |
---|
547 | |
---|
548 | #ifdef HESIOD |
---|
549 | nmaps = switch_map_find("passwd", maptype, mapreturn); |
---|
550 | UseHesiod = FALSE; |
---|
551 | if (nmaps > 0 && nmaps <= MAXMAPSTACK) |
---|
552 | { |
---|
553 | register int mapno; |
---|
554 | |
---|
555 | for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) |
---|
556 | { |
---|
557 | if (strcmp(maptype[mapno], "hesiod") == 0) |
---|
558 | UseHesiod = TRUE; |
---|
559 | } |
---|
560 | } |
---|
561 | #endif |
---|
562 | } |
---|
563 | } |
---|
564 | /* |
---|
565 | ** TRANSLATE_DOLLARS -- convert $x into internal form |
---|
566 | ** |
---|
567 | ** Actually does all appropriate pre-processing of a config line |
---|
568 | ** to turn it into internal form. |
---|
569 | ** |
---|
570 | ** Parameters: |
---|
571 | ** bp -- the buffer to translate. |
---|
572 | ** |
---|
573 | ** Returns: |
---|
574 | ** None. The buffer is translated in place. Since the |
---|
575 | ** translations always make the buffer shorter, this is |
---|
576 | ** safe without a size parameter. |
---|
577 | */ |
---|
578 | |
---|
579 | void |
---|
580 | translate_dollars(bp) |
---|
581 | char *bp; |
---|
582 | { |
---|
583 | register char *p; |
---|
584 | auto char *ep; |
---|
585 | |
---|
586 | for (p = bp; *p != '\0'; p++) |
---|
587 | { |
---|
588 | if (*p == '#' && p > bp && ConfigLevel >= 3) |
---|
589 | { |
---|
590 | /* this is an on-line comment */ |
---|
591 | register char *e; |
---|
592 | |
---|
593 | switch (*--p & 0377) |
---|
594 | { |
---|
595 | case MACROEXPAND: |
---|
596 | /* it's from $# -- let it go through */ |
---|
597 | p++; |
---|
598 | break; |
---|
599 | |
---|
600 | case '\\': |
---|
601 | /* it's backslash escaped */ |
---|
602 | (void) strcpy(p, p + 1); |
---|
603 | break; |
---|
604 | |
---|
605 | default: |
---|
606 | /* delete preceeding white space */ |
---|
607 | while (isascii(*p) && isspace(*p) && |
---|
608 | *p != '\n' && p > bp) |
---|
609 | p--; |
---|
610 | if ((e = strchr(++p, '\n')) != NULL) |
---|
611 | (void) strcpy(p, e); |
---|
612 | else |
---|
613 | *p-- = '\0'; |
---|
614 | break; |
---|
615 | } |
---|
616 | continue; |
---|
617 | } |
---|
618 | |
---|
619 | if (*p != '$' || p[1] == '\0') |
---|
620 | continue; |
---|
621 | |
---|
622 | if (p[1] == '$') |
---|
623 | { |
---|
624 | /* actual dollar sign.... */ |
---|
625 | (void) strcpy(p, p + 1); |
---|
626 | continue; |
---|
627 | } |
---|
628 | |
---|
629 | /* convert to macro expansion character */ |
---|
630 | *p++ = MACROEXPAND; |
---|
631 | |
---|
632 | /* special handling for $=, $~, $&, and $? */ |
---|
633 | if (*p == '=' || *p == '~' || *p == '&' || *p == '?') |
---|
634 | p++; |
---|
635 | |
---|
636 | /* convert macro name to code */ |
---|
637 | *p = macid(p, &ep); |
---|
638 | if (ep != p) |
---|
639 | strcpy(p + 1, ep); |
---|
640 | } |
---|
641 | |
---|
642 | /* strip trailing white space from the line */ |
---|
643 | while (--p > bp && isascii(*p) && isspace(*p)) |
---|
644 | *p = '\0'; |
---|
645 | } |
---|
646 | /* |
---|
647 | ** TOOMANY -- signal too many of some option |
---|
648 | ** |
---|
649 | ** Parameters: |
---|
650 | ** id -- the id of the error line |
---|
651 | ** maxcnt -- the maximum possible values |
---|
652 | ** |
---|
653 | ** Returns: |
---|
654 | ** none. |
---|
655 | ** |
---|
656 | ** Side Effects: |
---|
657 | ** gives a syserr. |
---|
658 | */ |
---|
659 | |
---|
660 | void |
---|
661 | toomany(id, maxcnt) |
---|
662 | int id; |
---|
663 | int maxcnt; |
---|
664 | { |
---|
665 | syserr("too many %c lines, %d max", id, maxcnt); |
---|
666 | } |
---|
667 | /* |
---|
668 | ** FILECLASS -- read members of a class from a file |
---|
669 | ** |
---|
670 | ** Parameters: |
---|
671 | ** class -- class to define. |
---|
672 | ** filename -- name of file to read. |
---|
673 | ** fmt -- scanf string to use for match. |
---|
674 | ** safe -- if set, this is a safe read. |
---|
675 | ** optional -- if set, it is not an error for the file to |
---|
676 | ** not exist. |
---|
677 | ** |
---|
678 | ** Returns: |
---|
679 | ** none |
---|
680 | ** |
---|
681 | ** Side Effects: |
---|
682 | ** |
---|
683 | ** puts all lines in filename that match a scanf into |
---|
684 | ** the named class. |
---|
685 | */ |
---|
686 | |
---|
687 | void |
---|
688 | fileclass(class, filename, fmt, safe, optional) |
---|
689 | int class; |
---|
690 | char *filename; |
---|
691 | char *fmt; |
---|
692 | bool safe; |
---|
693 | bool optional; |
---|
694 | { |
---|
695 | FILE *f; |
---|
696 | int sff; |
---|
697 | pid_t pid; |
---|
698 | register char *p; |
---|
699 | char buf[MAXLINE]; |
---|
700 | |
---|
701 | if (tTd(37, 2)) |
---|
702 | printf("fileclass(%s, fmt=%s)\n", filename, fmt); |
---|
703 | |
---|
704 | if (filename[0] == '|') |
---|
705 | { |
---|
706 | auto int fd; |
---|
707 | int i; |
---|
708 | char *argv[MAXPV + 1]; |
---|
709 | |
---|
710 | i = 0; |
---|
711 | for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) |
---|
712 | { |
---|
713 | if (i >= MAXPV) |
---|
714 | break; |
---|
715 | argv[i++] = p; |
---|
716 | } |
---|
717 | argv[i] = NULL; |
---|
718 | pid = prog_open(argv, &fd, CurEnv); |
---|
719 | if (pid < 0) |
---|
720 | f = NULL; |
---|
721 | else |
---|
722 | f = fdopen(fd, "r"); |
---|
723 | } |
---|
724 | else |
---|
725 | { |
---|
726 | pid = -1; |
---|
727 | sff = SFF_REGONLY; |
---|
728 | if (!bitset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail)) |
---|
729 | sff |= SFF_SAFEDIRPATH; |
---|
730 | if (!bitset(DBS_LINKEDCLASSFILEINWRITABLEDIR, DontBlameSendmail)) |
---|
731 | sff |= SFF_NOWLINK; |
---|
732 | if (safe) |
---|
733 | sff |= SFF_OPENASROOT; |
---|
734 | if (DontLockReadFiles) |
---|
735 | sff |= SFF_NOLOCK; |
---|
736 | f = safefopen(filename, O_RDONLY, 0, sff); |
---|
737 | } |
---|
738 | if (f == NULL) |
---|
739 | { |
---|
740 | if (!optional) |
---|
741 | syserr("fileclass: cannot open %s", filename); |
---|
742 | return; |
---|
743 | } |
---|
744 | |
---|
745 | while (fgets(buf, sizeof buf, f) != NULL) |
---|
746 | { |
---|
747 | register char *p; |
---|
748 | # if SCANF |
---|
749 | char wordbuf[MAXLINE + 1]; |
---|
750 | # endif |
---|
751 | |
---|
752 | if (buf[0] == '#') |
---|
753 | continue; |
---|
754 | # if SCANF |
---|
755 | if (sscanf(buf, fmt, wordbuf) != 1) |
---|
756 | continue; |
---|
757 | p = wordbuf; |
---|
758 | # else /* SCANF */ |
---|
759 | p = buf; |
---|
760 | # endif /* SCANF */ |
---|
761 | |
---|
762 | /* |
---|
763 | ** Break up the match into words. |
---|
764 | */ |
---|
765 | |
---|
766 | while (*p != '\0') |
---|
767 | { |
---|
768 | register char *q; |
---|
769 | |
---|
770 | /* strip leading spaces */ |
---|
771 | while (isascii(*p) && isspace(*p)) |
---|
772 | p++; |
---|
773 | if (*p == '\0') |
---|
774 | break; |
---|
775 | |
---|
776 | /* find the end of the word */ |
---|
777 | q = p; |
---|
778 | while (*p != '\0' && !(isascii(*p) && isspace(*p))) |
---|
779 | p++; |
---|
780 | if (*p != '\0') |
---|
781 | *p++ = '\0'; |
---|
782 | |
---|
783 | /* enter the word in the symbol table */ |
---|
784 | setclass(class, q); |
---|
785 | } |
---|
786 | } |
---|
787 | |
---|
788 | (void) fclose(f); |
---|
789 | if (pid > 0) |
---|
790 | (void) waitfor(pid); |
---|
791 | } |
---|
792 | /* |
---|
793 | ** MAKEMAILER -- define a new mailer. |
---|
794 | ** |
---|
795 | ** Parameters: |
---|
796 | ** line -- description of mailer. This is in labeled |
---|
797 | ** fields. The fields are: |
---|
798 | ** A -- the argv for this mailer |
---|
799 | ** C -- the character set for MIME conversions |
---|
800 | ** D -- the directory to run in |
---|
801 | ** E -- the eol string |
---|
802 | ** F -- the flags associated with the mailer |
---|
803 | ** L -- the maximum line length |
---|
804 | ** M -- the maximum message size |
---|
805 | ** N -- the niceness at which to run |
---|
806 | ** P -- the path to the mailer |
---|
807 | ** R -- the recipient rewriting set |
---|
808 | ** S -- the sender rewriting set |
---|
809 | ** T -- the mailer type (for DSNs) |
---|
810 | ** U -- the uid to run as |
---|
811 | ** The first word is the canonical name of the mailer. |
---|
812 | ** |
---|
813 | ** Returns: |
---|
814 | ** none. |
---|
815 | ** |
---|
816 | ** Side Effects: |
---|
817 | ** enters the mailer into the mailer table. |
---|
818 | */ |
---|
819 | |
---|
820 | void |
---|
821 | makemailer(line) |
---|
822 | char *line; |
---|
823 | { |
---|
824 | register char *p; |
---|
825 | register struct mailer *m; |
---|
826 | register STAB *s; |
---|
827 | int i; |
---|
828 | char fcode; |
---|
829 | auto char *endp; |
---|
830 | extern int NextMailer; |
---|
831 | extern char **makeargv __P((char *)); |
---|
832 | extern char *munchstring __P((char *, char **, int)); |
---|
833 | |
---|
834 | /* allocate a mailer and set up defaults */ |
---|
835 | m = (struct mailer *) xalloc(sizeof *m); |
---|
836 | bzero((char *) m, sizeof *m); |
---|
837 | |
---|
838 | /* collect the mailer name */ |
---|
839 | for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) |
---|
840 | continue; |
---|
841 | if (*p != '\0') |
---|
842 | *p++ = '\0'; |
---|
843 | if (line[0] == '\0') |
---|
844 | syserr("name required for mailer"); |
---|
845 | m->m_name = newstr(line); |
---|
846 | |
---|
847 | /* now scan through and assign info from the fields */ |
---|
848 | while (*p != '\0') |
---|
849 | { |
---|
850 | auto char *delimptr; |
---|
851 | |
---|
852 | while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) |
---|
853 | p++; |
---|
854 | |
---|
855 | /* p now points to field code */ |
---|
856 | fcode = *p; |
---|
857 | while (*p != '\0' && *p != '=' && *p != ',') |
---|
858 | p++; |
---|
859 | if (*p++ != '=') |
---|
860 | { |
---|
861 | syserr("mailer %s: `=' expected", m->m_name); |
---|
862 | return; |
---|
863 | } |
---|
864 | while (isascii(*p) && isspace(*p)) |
---|
865 | p++; |
---|
866 | |
---|
867 | /* p now points to the field body */ |
---|
868 | p = munchstring(p, &delimptr, ','); |
---|
869 | |
---|
870 | /* install the field into the mailer struct */ |
---|
871 | switch (fcode) |
---|
872 | { |
---|
873 | case 'P': /* pathname */ |
---|
874 | if (*p == '\0') |
---|
875 | syserr("mailer %s: empty path name", m->m_name); |
---|
876 | m->m_mailer = newstr(p); |
---|
877 | break; |
---|
878 | |
---|
879 | case 'F': /* flags */ |
---|
880 | for (; *p != '\0'; p++) |
---|
881 | if (!(isascii(*p) && isspace(*p))) |
---|
882 | setbitn(*p, m->m_flags); |
---|
883 | break; |
---|
884 | |
---|
885 | case 'S': /* sender rewriting ruleset */ |
---|
886 | case 'R': /* recipient rewriting ruleset */ |
---|
887 | i = strtorwset(p, &endp, ST_ENTER); |
---|
888 | if (i < 0) |
---|
889 | return; |
---|
890 | if (fcode == 'S') |
---|
891 | m->m_sh_rwset = m->m_se_rwset = i; |
---|
892 | else |
---|
893 | m->m_rh_rwset = m->m_re_rwset = i; |
---|
894 | |
---|
895 | p = endp; |
---|
896 | if (*p++ == '/') |
---|
897 | { |
---|
898 | i = strtorwset(p, NULL, ST_ENTER); |
---|
899 | if (i < 0) |
---|
900 | return; |
---|
901 | if (fcode == 'S') |
---|
902 | m->m_sh_rwset = i; |
---|
903 | else |
---|
904 | m->m_rh_rwset = i; |
---|
905 | } |
---|
906 | break; |
---|
907 | |
---|
908 | case 'E': /* end of line string */ |
---|
909 | if (*p == '\0') |
---|
910 | syserr("mailer %s: null end-of-line string", |
---|
911 | m->m_name); |
---|
912 | m->m_eol = newstr(p); |
---|
913 | break; |
---|
914 | |
---|
915 | case 'A': /* argument vector */ |
---|
916 | if (*p == '\0') |
---|
917 | syserr("mailer %s: null argument vector", |
---|
918 | m->m_name); |
---|
919 | m->m_argv = makeargv(p); |
---|
920 | break; |
---|
921 | |
---|
922 | case 'M': /* maximum message size */ |
---|
923 | m->m_maxsize = atol(p); |
---|
924 | break; |
---|
925 | |
---|
926 | case 'L': /* maximum line length */ |
---|
927 | m->m_linelimit = atoi(p); |
---|
928 | if (m->m_linelimit < 0) |
---|
929 | m->m_linelimit = 0; |
---|
930 | break; |
---|
931 | |
---|
932 | case 'N': /* run niceness */ |
---|
933 | m->m_nice = atoi(p); |
---|
934 | break; |
---|
935 | |
---|
936 | case 'D': /* working directory */ |
---|
937 | if (*p == '\0') |
---|
938 | syserr("mailer %s: null working directory", |
---|
939 | m->m_name); |
---|
940 | m->m_execdir = newstr(p); |
---|
941 | break; |
---|
942 | |
---|
943 | case 'C': /* default charset */ |
---|
944 | if (*p == '\0') |
---|
945 | syserr("mailer %s: null charset", m->m_name); |
---|
946 | m->m_defcharset = newstr(p); |
---|
947 | break; |
---|
948 | |
---|
949 | case 'T': /* MTA-Name/Address/Diagnostic types */ |
---|
950 | /* extract MTA name type; default to "dns" */ |
---|
951 | m->m_mtatype = newstr(p); |
---|
952 | p = strchr(m->m_mtatype, '/'); |
---|
953 | if (p != NULL) |
---|
954 | { |
---|
955 | *p++ = '\0'; |
---|
956 | if (*p == '\0') |
---|
957 | p = NULL; |
---|
958 | } |
---|
959 | if (*m->m_mtatype == '\0') |
---|
960 | m->m_mtatype = "dns"; |
---|
961 | |
---|
962 | /* extract address type; default to "rfc822" */ |
---|
963 | m->m_addrtype = p; |
---|
964 | if (p != NULL) |
---|
965 | p = strchr(p, '/'); |
---|
966 | if (p != NULL) |
---|
967 | { |
---|
968 | *p++ = '\0'; |
---|
969 | if (*p == '\0') |
---|
970 | p = NULL; |
---|
971 | } |
---|
972 | if (m->m_addrtype == NULL || *m->m_addrtype == '\0') |
---|
973 | m->m_addrtype = "rfc822"; |
---|
974 | |
---|
975 | /* extract diagnostic type; default to "smtp" */ |
---|
976 | m->m_diagtype = p; |
---|
977 | if (m->m_diagtype == NULL || *m->m_diagtype == '\0') |
---|
978 | m->m_diagtype = "smtp"; |
---|
979 | break; |
---|
980 | |
---|
981 | case 'U': /* user id */ |
---|
982 | if (isascii(*p) && !isdigit(*p)) |
---|
983 | { |
---|
984 | char *q = p; |
---|
985 | struct passwd *pw; |
---|
986 | |
---|
987 | while (*p != '\0' && isascii(*p) && |
---|
988 | (isalnum(*p) || strchr("-_", *p) != NULL)) |
---|
989 | p++; |
---|
990 | while (isascii(*p) && isspace(*p)) |
---|
991 | *p++ = '\0'; |
---|
992 | if (*p != '\0') |
---|
993 | *p++ = '\0'; |
---|
994 | if (*q == '\0') |
---|
995 | syserr("mailer %s: null user name", |
---|
996 | m->m_name); |
---|
997 | pw = sm_getpwnam(q); |
---|
998 | if (pw == NULL) |
---|
999 | syserr("readcf: mailer U= flag: unknown user %s", q); |
---|
1000 | else |
---|
1001 | { |
---|
1002 | m->m_uid = pw->pw_uid; |
---|
1003 | m->m_gid = pw->pw_gid; |
---|
1004 | } |
---|
1005 | } |
---|
1006 | else |
---|
1007 | { |
---|
1008 | auto char *q; |
---|
1009 | |
---|
1010 | m->m_uid = strtol(p, &q, 0); |
---|
1011 | p = q; |
---|
1012 | while (isascii(*p) && isspace(*p)) |
---|
1013 | p++; |
---|
1014 | if (*p != '\0') |
---|
1015 | p++; |
---|
1016 | } |
---|
1017 | while (isascii(*p) && isspace(*p)) |
---|
1018 | p++; |
---|
1019 | if (*p == '\0') |
---|
1020 | break; |
---|
1021 | if (isascii(*p) && !isdigit(*p)) |
---|
1022 | { |
---|
1023 | char *q = p; |
---|
1024 | struct group *gr; |
---|
1025 | |
---|
1026 | while (isascii(*p) && isalnum(*p)) |
---|
1027 | p++; |
---|
1028 | *p++ = '\0'; |
---|
1029 | if (*q == '\0') |
---|
1030 | syserr("mailer %s: null group name", |
---|
1031 | m->m_name); |
---|
1032 | gr = getgrnam(q); |
---|
1033 | if (gr == NULL) |
---|
1034 | syserr("readcf: mailer U= flag: unknown group %s", q); |
---|
1035 | else |
---|
1036 | m->m_gid = gr->gr_gid; |
---|
1037 | } |
---|
1038 | else |
---|
1039 | { |
---|
1040 | m->m_gid = strtol(p, NULL, 0); |
---|
1041 | } |
---|
1042 | break; |
---|
1043 | } |
---|
1044 | |
---|
1045 | p = delimptr; |
---|
1046 | } |
---|
1047 | |
---|
1048 | /* do some rationality checking */ |
---|
1049 | if (m->m_argv == NULL) |
---|
1050 | { |
---|
1051 | syserr("M%s: A= argument required", m->m_name); |
---|
1052 | return; |
---|
1053 | } |
---|
1054 | if (m->m_mailer == NULL) |
---|
1055 | { |
---|
1056 | syserr("M%s: P= argument required", m->m_name); |
---|
1057 | return; |
---|
1058 | } |
---|
1059 | |
---|
1060 | if (NextMailer >= MAXMAILERS) |
---|
1061 | { |
---|
1062 | syserr("too many mailers defined (%d max)", MAXMAILERS); |
---|
1063 | return; |
---|
1064 | } |
---|
1065 | |
---|
1066 | /* do some heuristic cleanup for back compatibility */ |
---|
1067 | if (bitnset(M_LIMITS, m->m_flags)) |
---|
1068 | { |
---|
1069 | if (m->m_linelimit == 0) |
---|
1070 | m->m_linelimit = SMTPLINELIM; |
---|
1071 | if (ConfigLevel < 2) |
---|
1072 | setbitn(M_7BITS, m->m_flags); |
---|
1073 | } |
---|
1074 | |
---|
1075 | if (strcmp(m->m_mailer, "[IPC]") == 0 || |
---|
1076 | strcmp(m->m_mailer, "[TCP]") == 0) |
---|
1077 | { |
---|
1078 | if (m->m_mtatype == NULL) |
---|
1079 | m->m_mtatype = "dns"; |
---|
1080 | if (m->m_addrtype == NULL) |
---|
1081 | m->m_addrtype = "rfc822"; |
---|
1082 | if (m->m_diagtype == NULL) |
---|
1083 | m->m_diagtype = "smtp"; |
---|
1084 | } |
---|
1085 | |
---|
1086 | if (strcmp(m->m_mailer, "[FILE]") == 0) |
---|
1087 | { |
---|
1088 | /* Use the second argument for filename */ |
---|
1089 | if (m->m_argv[0] == NULL || m->m_argv[1] == NULL || |
---|
1090 | m->m_argv[2] != NULL) |
---|
1091 | { |
---|
1092 | syserr("M%s: too %s parameters for [FILE] mailer", |
---|
1093 | m->m_name, |
---|
1094 | (m->m_argv[0] == NULL || |
---|
1095 | m->m_argv[1] == NULL) ? "few" : "many"); |
---|
1096 | } |
---|
1097 | else if (strcmp(m->m_argv[0], "FILE") != 0) |
---|
1098 | { |
---|
1099 | syserr("M%s: first argument in [FILE] mailer must be FILE", |
---|
1100 | m->m_name); |
---|
1101 | } |
---|
1102 | } |
---|
1103 | |
---|
1104 | if (m->m_eol == NULL) |
---|
1105 | { |
---|
1106 | char **pp; |
---|
1107 | |
---|
1108 | /* default for SMTP is \r\n; use \n for local delivery */ |
---|
1109 | for (pp = m->m_argv; *pp != NULL; pp++) |
---|
1110 | { |
---|
1111 | char *p; |
---|
1112 | |
---|
1113 | for (p = *pp; *p != '\0'; ) |
---|
1114 | { |
---|
1115 | if ((*p++ & 0377) == MACROEXPAND && *p == 'u') |
---|
1116 | break; |
---|
1117 | } |
---|
1118 | if (*p != '\0') |
---|
1119 | break; |
---|
1120 | } |
---|
1121 | if (*pp == NULL) |
---|
1122 | m->m_eol = "\r\n"; |
---|
1123 | else |
---|
1124 | m->m_eol = "\n"; |
---|
1125 | } |
---|
1126 | |
---|
1127 | /* enter the mailer into the symbol table */ |
---|
1128 | s = stab(m->m_name, ST_MAILER, ST_ENTER); |
---|
1129 | if (s->s_mailer != NULL) |
---|
1130 | { |
---|
1131 | i = s->s_mailer->m_mno; |
---|
1132 | free(s->s_mailer); |
---|
1133 | } |
---|
1134 | else |
---|
1135 | { |
---|
1136 | i = NextMailer++; |
---|
1137 | } |
---|
1138 | Mailer[i] = s->s_mailer = m; |
---|
1139 | m->m_mno = i; |
---|
1140 | } |
---|
1141 | /* |
---|
1142 | ** MUNCHSTRING -- translate a string into internal form. |
---|
1143 | ** |
---|
1144 | ** Parameters: |
---|
1145 | ** p -- the string to munch. |
---|
1146 | ** delimptr -- if non-NULL, set to the pointer of the |
---|
1147 | ** field delimiter character. |
---|
1148 | ** delim -- the delimiter for the field. |
---|
1149 | ** |
---|
1150 | ** Returns: |
---|
1151 | ** the munched string. |
---|
1152 | */ |
---|
1153 | |
---|
1154 | char * |
---|
1155 | munchstring(p, delimptr, delim) |
---|
1156 | register char *p; |
---|
1157 | char **delimptr; |
---|
1158 | int delim; |
---|
1159 | { |
---|
1160 | register char *q; |
---|
1161 | bool backslash = FALSE; |
---|
1162 | bool quotemode = FALSE; |
---|
1163 | static char buf[MAXLINE]; |
---|
1164 | |
---|
1165 | for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++) |
---|
1166 | { |
---|
1167 | if (backslash) |
---|
1168 | { |
---|
1169 | /* everything is roughly literal */ |
---|
1170 | backslash = FALSE; |
---|
1171 | switch (*p) |
---|
1172 | { |
---|
1173 | case 'r': /* carriage return */ |
---|
1174 | *q++ = '\r'; |
---|
1175 | continue; |
---|
1176 | |
---|
1177 | case 'n': /* newline */ |
---|
1178 | *q++ = '\n'; |
---|
1179 | continue; |
---|
1180 | |
---|
1181 | case 'f': /* form feed */ |
---|
1182 | *q++ = '\f'; |
---|
1183 | continue; |
---|
1184 | |
---|
1185 | case 'b': /* backspace */ |
---|
1186 | *q++ = '\b'; |
---|
1187 | continue; |
---|
1188 | } |
---|
1189 | *q++ = *p; |
---|
1190 | } |
---|
1191 | else |
---|
1192 | { |
---|
1193 | if (*p == '\\') |
---|
1194 | backslash = TRUE; |
---|
1195 | else if (*p == '"') |
---|
1196 | quotemode = !quotemode; |
---|
1197 | else if (quotemode || *p != delim) |
---|
1198 | *q++ = *p; |
---|
1199 | else |
---|
1200 | break; |
---|
1201 | } |
---|
1202 | } |
---|
1203 | |
---|
1204 | if (delimptr != NULL) |
---|
1205 | *delimptr = p; |
---|
1206 | *q++ = '\0'; |
---|
1207 | return (buf); |
---|
1208 | } |
---|
1209 | /* |
---|
1210 | ** MAKEARGV -- break up a string into words |
---|
1211 | ** |
---|
1212 | ** Parameters: |
---|
1213 | ** p -- the string to break up. |
---|
1214 | ** |
---|
1215 | ** Returns: |
---|
1216 | ** a char **argv (dynamically allocated) |
---|
1217 | ** |
---|
1218 | ** Side Effects: |
---|
1219 | ** munges p. |
---|
1220 | */ |
---|
1221 | |
---|
1222 | char ** |
---|
1223 | makeargv(p) |
---|
1224 | register char *p; |
---|
1225 | { |
---|
1226 | char *q; |
---|
1227 | int i; |
---|
1228 | char **avp; |
---|
1229 | char *argv[MAXPV + 1]; |
---|
1230 | |
---|
1231 | /* take apart the words */ |
---|
1232 | i = 0; |
---|
1233 | while (*p != '\0' && i < MAXPV) |
---|
1234 | { |
---|
1235 | q = p; |
---|
1236 | while (*p != '\0' && !(isascii(*p) && isspace(*p))) |
---|
1237 | p++; |
---|
1238 | while (isascii(*p) && isspace(*p)) |
---|
1239 | *p++ = '\0'; |
---|
1240 | argv[i++] = newstr(q); |
---|
1241 | } |
---|
1242 | argv[i++] = NULL; |
---|
1243 | |
---|
1244 | /* now make a copy of the argv */ |
---|
1245 | avp = (char **) xalloc(sizeof *avp * i); |
---|
1246 | bcopy((char *) argv, (char *) avp, sizeof *avp * i); |
---|
1247 | |
---|
1248 | return (avp); |
---|
1249 | } |
---|
1250 | /* |
---|
1251 | ** PRINTRULES -- print rewrite rules (for debugging) |
---|
1252 | ** |
---|
1253 | ** Parameters: |
---|
1254 | ** none. |
---|
1255 | ** |
---|
1256 | ** Returns: |
---|
1257 | ** none. |
---|
1258 | ** |
---|
1259 | ** Side Effects: |
---|
1260 | ** prints rewrite rules. |
---|
1261 | */ |
---|
1262 | |
---|
1263 | void |
---|
1264 | printrules() |
---|
1265 | { |
---|
1266 | register struct rewrite *rwp; |
---|
1267 | register int ruleset; |
---|
1268 | |
---|
1269 | for (ruleset = 0; ruleset < 10; ruleset++) |
---|
1270 | { |
---|
1271 | if (RewriteRules[ruleset] == NULL) |
---|
1272 | continue; |
---|
1273 | printf("\n----Rule Set %d:", ruleset); |
---|
1274 | |
---|
1275 | for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) |
---|
1276 | { |
---|
1277 | printf("\nLHS:"); |
---|
1278 | printav(rwp->r_lhs); |
---|
1279 | printf("RHS:"); |
---|
1280 | printav(rwp->r_rhs); |
---|
1281 | } |
---|
1282 | } |
---|
1283 | } |
---|
1284 | /* |
---|
1285 | ** PRINTMAILER -- print mailer structure (for debugging) |
---|
1286 | ** |
---|
1287 | ** Parameters: |
---|
1288 | ** m -- the mailer to print |
---|
1289 | ** |
---|
1290 | ** Returns: |
---|
1291 | ** none. |
---|
1292 | */ |
---|
1293 | |
---|
1294 | void |
---|
1295 | printmailer(m) |
---|
1296 | register MAILER *m; |
---|
1297 | { |
---|
1298 | int j; |
---|
1299 | |
---|
1300 | printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", |
---|
1301 | m->m_mno, m->m_name, |
---|
1302 | m->m_mailer, m->m_se_rwset, m->m_sh_rwset, |
---|
1303 | m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, |
---|
1304 | (int) m->m_uid, (int) m->m_gid); |
---|
1305 | for (j = '\0'; j <= '\177'; j++) |
---|
1306 | if (bitnset(j, m->m_flags)) |
---|
1307 | (void) putchar(j); |
---|
1308 | printf(" L=%d E=", m->m_linelimit); |
---|
1309 | xputs(m->m_eol); |
---|
1310 | if (m->m_defcharset != NULL) |
---|
1311 | printf(" C=%s", m->m_defcharset); |
---|
1312 | printf(" T=%s/%s/%s", |
---|
1313 | m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, |
---|
1314 | m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, |
---|
1315 | m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); |
---|
1316 | if (m->m_argv != NULL) |
---|
1317 | { |
---|
1318 | char **a = m->m_argv; |
---|
1319 | |
---|
1320 | printf(" A="); |
---|
1321 | while (*a != NULL) |
---|
1322 | { |
---|
1323 | if (a != m->m_argv) |
---|
1324 | printf(" "); |
---|
1325 | xputs(*a++); |
---|
1326 | } |
---|
1327 | } |
---|
1328 | printf("\n"); |
---|
1329 | } |
---|
1330 | /* |
---|
1331 | ** SETOPTION -- set global processing option |
---|
1332 | ** |
---|
1333 | ** Parameters: |
---|
1334 | ** opt -- option name. |
---|
1335 | ** val -- option value (as a text string). |
---|
1336 | ** safe -- set if this came from a configuration file. |
---|
1337 | ** Some options (if set from the command line) will |
---|
1338 | ** reset the user id to avoid security problems. |
---|
1339 | ** sticky -- if set, don't let other setoptions override |
---|
1340 | ** this value. |
---|
1341 | ** e -- the main envelope. |
---|
1342 | ** |
---|
1343 | ** Returns: |
---|
1344 | ** none. |
---|
1345 | ** |
---|
1346 | ** Side Effects: |
---|
1347 | ** Sets options as implied by the arguments. |
---|
1348 | */ |
---|
1349 | |
---|
1350 | static BITMAP StickyOpt; /* set if option is stuck */ |
---|
1351 | extern void settimeout __P((char *, char *)); |
---|
1352 | |
---|
1353 | |
---|
1354 | #if NAMED_BIND |
---|
1355 | |
---|
1356 | struct resolverflags |
---|
1357 | { |
---|
1358 | char *rf_name; /* name of the flag */ |
---|
1359 | long rf_bits; /* bits to set/clear */ |
---|
1360 | } ResolverFlags[] = |
---|
1361 | { |
---|
1362 | { "debug", RES_DEBUG }, |
---|
1363 | { "aaonly", RES_AAONLY }, |
---|
1364 | { "usevc", RES_USEVC }, |
---|
1365 | { "primary", RES_PRIMARY }, |
---|
1366 | { "igntc", RES_IGNTC }, |
---|
1367 | { "recurse", RES_RECURSE }, |
---|
1368 | { "defnames", RES_DEFNAMES }, |
---|
1369 | { "stayopen", RES_STAYOPEN }, |
---|
1370 | { "dnsrch", RES_DNSRCH }, |
---|
1371 | { "true", 0 }, /* avoid error on old syntax */ |
---|
1372 | { NULL, 0 } |
---|
1373 | }; |
---|
1374 | |
---|
1375 | #endif |
---|
1376 | |
---|
1377 | struct optioninfo |
---|
1378 | { |
---|
1379 | char *o_name; /* long name of option */ |
---|
1380 | u_char o_code; /* short name of option */ |
---|
1381 | bool o_safe; /* safe for random people to use */ |
---|
1382 | } OptionTab[] = |
---|
1383 | { |
---|
1384 | { "SevenBitInput", '7', TRUE }, |
---|
1385 | #if MIME8TO7 |
---|
1386 | { "EightBitMode", '8', TRUE }, |
---|
1387 | #endif |
---|
1388 | { "AliasFile", 'A', FALSE }, |
---|
1389 | { "AliasWait", 'a', FALSE }, |
---|
1390 | { "BlankSub", 'B', FALSE }, |
---|
1391 | { "MinFreeBlocks", 'b', TRUE }, |
---|
1392 | { "CheckpointInterval", 'C', TRUE }, |
---|
1393 | { "HoldExpensive", 'c', FALSE }, |
---|
1394 | { "AutoRebuildAliases", 'D', FALSE }, |
---|
1395 | { "DeliveryMode", 'd', TRUE }, |
---|
1396 | { "ErrorHeader", 'E', FALSE }, |
---|
1397 | { "ErrorMode", 'e', TRUE }, |
---|
1398 | { "TempFileMode", 'F', FALSE }, |
---|
1399 | { "SaveFromLine", 'f', FALSE }, |
---|
1400 | { "MatchGECOS", 'G', FALSE }, |
---|
1401 | { "HelpFile", 'H', FALSE }, |
---|
1402 | { "MaxHopCount", 'h', FALSE }, |
---|
1403 | { "ResolverOptions", 'I', FALSE }, |
---|
1404 | { "IgnoreDots", 'i', TRUE }, |
---|
1405 | { "ForwardPath", 'J', FALSE }, |
---|
1406 | { "SendMimeErrors", 'j', TRUE }, |
---|
1407 | { "ConnectionCacheSize", 'k', FALSE }, |
---|
1408 | { "ConnectionCacheTimeout", 'K', FALSE }, |
---|
1409 | { "UseErrorsTo", 'l', FALSE }, |
---|
1410 | { "LogLevel", 'L', TRUE }, |
---|
1411 | { "MeToo", 'm', TRUE }, |
---|
1412 | { "CheckAliases", 'n', FALSE }, |
---|
1413 | { "OldStyleHeaders", 'o', TRUE }, |
---|
1414 | { "DaemonPortOptions", 'O', FALSE }, |
---|
1415 | { "PrivacyOptions", 'p', TRUE }, |
---|
1416 | { "PostmasterCopy", 'P', FALSE }, |
---|
1417 | { "QueueFactor", 'q', FALSE }, |
---|
1418 | { "QueueDirectory", 'Q', FALSE }, |
---|
1419 | { "DontPruneRoutes", 'R', FALSE }, |
---|
1420 | { "Timeout", 'r', FALSE }, |
---|
1421 | { "StatusFile", 'S', FALSE }, |
---|
1422 | { "SuperSafe", 's', TRUE }, |
---|
1423 | { "QueueTimeout", 'T', FALSE }, |
---|
1424 | { "TimeZoneSpec", 't', FALSE }, |
---|
1425 | { "UserDatabaseSpec", 'U', FALSE }, |
---|
1426 | { "DefaultUser", 'u', FALSE }, |
---|
1427 | { "FallbackMXhost", 'V', FALSE }, |
---|
1428 | { "Verbose", 'v', TRUE }, |
---|
1429 | { "TryNullMXList", 'w', FALSE }, |
---|
1430 | { "QueueLA", 'x', FALSE }, |
---|
1431 | { "RefuseLA", 'X', FALSE }, |
---|
1432 | { "RecipientFactor", 'y', FALSE }, |
---|
1433 | { "ForkEachJob", 'Y', FALSE }, |
---|
1434 | { "ClassFactor", 'z', FALSE }, |
---|
1435 | { "RetryFactor", 'Z', FALSE }, |
---|
1436 | #define O_QUEUESORTORD 0x81 |
---|
1437 | { "QueueSortOrder", O_QUEUESORTORD, TRUE }, |
---|
1438 | #define O_HOSTSFILE 0x82 |
---|
1439 | { "HostsFile", O_HOSTSFILE, FALSE }, |
---|
1440 | #define O_MQA 0x83 |
---|
1441 | { "MinQueueAge", O_MQA, TRUE }, |
---|
1442 | #define O_DEFCHARSET 0x85 |
---|
1443 | { "DefaultCharSet", O_DEFCHARSET, TRUE }, |
---|
1444 | #define O_SSFILE 0x86 |
---|
1445 | { "ServiceSwitchFile", O_SSFILE, FALSE }, |
---|
1446 | #define O_DIALDELAY 0x87 |
---|
1447 | { "DialDelay", O_DIALDELAY, TRUE }, |
---|
1448 | #define O_NORCPTACTION 0x88 |
---|
1449 | { "NoRecipientAction", O_NORCPTACTION, TRUE }, |
---|
1450 | #define O_SAFEFILEENV 0x89 |
---|
1451 | { "SafeFileEnvironment", O_SAFEFILEENV, FALSE }, |
---|
1452 | #define O_MAXMSGSIZE 0x8a |
---|
1453 | { "MaxMessageSize", O_MAXMSGSIZE, FALSE }, |
---|
1454 | #define O_COLONOKINADDR 0x8b |
---|
1455 | { "ColonOkInAddr", O_COLONOKINADDR, TRUE }, |
---|
1456 | #define O_MAXQUEUERUN 0x8c |
---|
1457 | { "MaxQueueRunSize", O_MAXQUEUERUN, TRUE }, |
---|
1458 | #define O_MAXCHILDREN 0x8d |
---|
1459 | { "MaxDaemonChildren", O_MAXCHILDREN, FALSE }, |
---|
1460 | #define O_KEEPCNAMES 0x8e |
---|
1461 | { "DontExpandCnames", O_KEEPCNAMES, FALSE }, |
---|
1462 | #define O_MUSTQUOTE 0x8f |
---|
1463 | { "MustQuoteChars", O_MUSTQUOTE, FALSE }, |
---|
1464 | #define O_SMTPGREETING 0x90 |
---|
1465 | { "SmtpGreetingMessage", O_SMTPGREETING, FALSE }, |
---|
1466 | #define O_UNIXFROM 0x91 |
---|
1467 | { "UnixFromLine", O_UNIXFROM, FALSE }, |
---|
1468 | #define O_OPCHARS 0x92 |
---|
1469 | { "OperatorChars", O_OPCHARS, FALSE }, |
---|
1470 | #define O_DONTINITGRPS 0x93 |
---|
1471 | { "DontInitGroups", O_DONTINITGRPS, FALSE }, |
---|
1472 | #define O_SLFH 0x94 |
---|
1473 | { "SingleLineFromHeader", O_SLFH, TRUE }, |
---|
1474 | #define O_ABH 0x95 |
---|
1475 | { "AllowBogusHELO", O_ABH, TRUE }, |
---|
1476 | #define O_CONNTHROT 0x97 |
---|
1477 | { "ConnectionRateThrottle", O_CONNTHROT, FALSE }, |
---|
1478 | #define O_UGW 0x99 |
---|
1479 | { "UnsafeGroupWrites", O_UGW, FALSE }, |
---|
1480 | #define O_DBLBOUNCE 0x9a |
---|
1481 | { "DoubleBounceAddress", O_DBLBOUNCE, FALSE }, |
---|
1482 | #define O_HSDIR 0x9b |
---|
1483 | { "HostStatusDirectory", O_HSDIR, FALSE }, |
---|
1484 | #define O_SINGTHREAD 0x9c |
---|
1485 | { "SingleThreadDelivery", O_SINGTHREAD, FALSE }, |
---|
1486 | #define O_RUNASUSER 0x9d |
---|
1487 | { "RunAsUser", O_RUNASUSER, FALSE }, |
---|
1488 | #if _FFR_DSN_RRT_OPTION |
---|
1489 | #define O_DSN_RRT 0x9e |
---|
1490 | { "RrtImpliesDsn", O_DSN_RRT, FALSE }, |
---|
1491 | #endif |
---|
1492 | #if _FFR_PIDFILE_OPTION |
---|
1493 | #define O_PIDFILE 0x9f |
---|
1494 | { "PidFile", O_PIDFILE, FALSE }, |
---|
1495 | #endif |
---|
1496 | #define O_DONTBLAMESENDMAIL 0xa0 |
---|
1497 | { "DontBlameSendmail", O_DONTBLAMESENDMAIL, FALSE }, |
---|
1498 | #define O_DPI 0xa1 |
---|
1499 | { "DontProbeInterfaces", O_DPI, FALSE }, |
---|
1500 | #define O_MAXRCPT 0xa2 |
---|
1501 | { "MaxRecipientsPerMessage", O_MAXRCPT, FALSE }, |
---|
1502 | #if _FFR_DEADLETTERDROP_OPTION |
---|
1503 | #define O_DEADLETTER 0xa3 |
---|
1504 | { "DeadLetterDrop", O_DEADLETTER, FALSE }, |
---|
1505 | #endif |
---|
1506 | #if _FFR_DONTLOCKFILESFORREAD_OPTION |
---|
1507 | #define O_DONTLOCK 0xa4 |
---|
1508 | { "DontLockFilesForRead", O_DONTLOCK, FALSE }, |
---|
1509 | #endif |
---|
1510 | #if _FFR_MAXALIASRECURSION_OPTION |
---|
1511 | #define O_MAXALIASRCSN 0xa5 |
---|
1512 | { "MaxAliasRecursion", O_MAXALIASRCSN, FALSE }, |
---|
1513 | #endif |
---|
1514 | #if _FFR_CONNECTONLYTO_OPTION |
---|
1515 | #define O_CNCTONLYTO 0xa6 |
---|
1516 | { "ConnectOnlyTo", O_CNCTONLYTO, FALSE }, |
---|
1517 | #endif |
---|
1518 | #if _FFR_TRUSTED_USER |
---|
1519 | #define O_TRUSTUSER 0xa7 |
---|
1520 | { "TrustedUser", O_TRUSTUSER, FALSE }, |
---|
1521 | #endif |
---|
1522 | #if _FFR_MAX_MIME_HEADER_LENGTH |
---|
1523 | #define O_MAXMIMEHDRLEN 0xa8 |
---|
1524 | { "MaxMimeHeaderLength", O_MAXMIMEHDRLEN, FALSE }, |
---|
1525 | #endif |
---|
1526 | #if _FFR_CONTROL_SOCKET |
---|
1527 | #define O_CONTROLSOCKET 0xa9 |
---|
1528 | { "ControlSocketName", O_CONTROLSOCKET, FALSE }, |
---|
1529 | #endif |
---|
1530 | #if _FFR_MAX_HEADERS_LENGTH |
---|
1531 | #define O_MAXHDRSLEN 0xaa |
---|
1532 | { "MaxHeadersLength", O_MAXHDRSLEN, FALSE }, |
---|
1533 | #endif |
---|
1534 | { NULL, '\0', FALSE } |
---|
1535 | }; |
---|
1536 | |
---|
1537 | |
---|
1538 | |
---|
1539 | void |
---|
1540 | setoption(opt, val, safe, sticky, e) |
---|
1541 | int opt; |
---|
1542 | char *val; |
---|
1543 | bool safe; |
---|
1544 | bool sticky; |
---|
1545 | register ENVELOPE *e; |
---|
1546 | { |
---|
1547 | register char *p; |
---|
1548 | register struct optioninfo *o; |
---|
1549 | char *subopt; |
---|
1550 | int mid; |
---|
1551 | bool can_setuid = RunAsUid == 0; |
---|
1552 | auto char *ep; |
---|
1553 | char buf[50]; |
---|
1554 | extern bool atobool __P((char *)); |
---|
1555 | extern time_t convtime __P((char *, char)); |
---|
1556 | extern int QueueLA; |
---|
1557 | extern int RefuseLA; |
---|
1558 | extern bool Warn_Q_option; |
---|
1559 | extern void setalias __P((char *)); |
---|
1560 | extern int atooct __P((char *)); |
---|
1561 | extern void setdefuser __P((void)); |
---|
1562 | extern void setdaemonoptions __P((char *)); |
---|
1563 | |
---|
1564 | errno = 0; |
---|
1565 | if (opt == ' ') |
---|
1566 | { |
---|
1567 | /* full word options */ |
---|
1568 | struct optioninfo *sel; |
---|
1569 | |
---|
1570 | p = strchr(val, '='); |
---|
1571 | if (p == NULL) |
---|
1572 | p = &val[strlen(val)]; |
---|
1573 | while (*--p == ' ') |
---|
1574 | continue; |
---|
1575 | while (*++p == ' ') |
---|
1576 | *p = '\0'; |
---|
1577 | if (p == val) |
---|
1578 | { |
---|
1579 | syserr("readcf: null option name"); |
---|
1580 | return; |
---|
1581 | } |
---|
1582 | if (*p == '=') |
---|
1583 | *p++ = '\0'; |
---|
1584 | while (*p == ' ') |
---|
1585 | p++; |
---|
1586 | subopt = strchr(val, '.'); |
---|
1587 | if (subopt != NULL) |
---|
1588 | *subopt++ = '\0'; |
---|
1589 | sel = NULL; |
---|
1590 | for (o = OptionTab; o->o_name != NULL; o++) |
---|
1591 | { |
---|
1592 | if (strncasecmp(o->o_name, val, strlen(val)) != 0) |
---|
1593 | continue; |
---|
1594 | if (strlen(o->o_name) == strlen(val)) |
---|
1595 | { |
---|
1596 | /* completely specified -- this must be it */ |
---|
1597 | sel = NULL; |
---|
1598 | break; |
---|
1599 | } |
---|
1600 | if (sel != NULL) |
---|
1601 | break; |
---|
1602 | sel = o; |
---|
1603 | } |
---|
1604 | if (sel != NULL && o->o_name == NULL) |
---|
1605 | o = sel; |
---|
1606 | else if (o->o_name == NULL) |
---|
1607 | { |
---|
1608 | syserr("readcf: unknown option name %s", val); |
---|
1609 | return; |
---|
1610 | } |
---|
1611 | else if (sel != NULL) |
---|
1612 | { |
---|
1613 | syserr("readcf: ambiguous option name %s (matches %s and %s)", |
---|
1614 | val, sel->o_name, o->o_name); |
---|
1615 | return; |
---|
1616 | } |
---|
1617 | if (strlen(val) != strlen(o->o_name)) |
---|
1618 | { |
---|
1619 | int oldVerbose = Verbose; |
---|
1620 | |
---|
1621 | Verbose = 1; |
---|
1622 | message("Option %s used as abbreviation for %s", |
---|
1623 | val, o->o_name); |
---|
1624 | Verbose = oldVerbose; |
---|
1625 | } |
---|
1626 | opt = o->o_code; |
---|
1627 | val = p; |
---|
1628 | } |
---|
1629 | else |
---|
1630 | { |
---|
1631 | for (o = OptionTab; o->o_name != NULL; o++) |
---|
1632 | { |
---|
1633 | if (o->o_code == opt) |
---|
1634 | break; |
---|
1635 | } |
---|
1636 | subopt = NULL; |
---|
1637 | } |
---|
1638 | |
---|
1639 | if (tTd(37, 1)) |
---|
1640 | { |
---|
1641 | printf(isascii(opt) && isprint(opt) ? |
---|
1642 | "setoption %s (%c).%s=" : |
---|
1643 | "setoption %s (0x%x).%s=", |
---|
1644 | o->o_name == NULL ? "<unknown>" : o->o_name, |
---|
1645 | opt, |
---|
1646 | subopt == NULL ? "" : subopt); |
---|
1647 | xputs(val); |
---|
1648 | } |
---|
1649 | |
---|
1650 | /* |
---|
1651 | ** See if this option is preset for us. |
---|
1652 | */ |
---|
1653 | |
---|
1654 | if (!sticky && bitnset(opt, StickyOpt)) |
---|
1655 | { |
---|
1656 | if (tTd(37, 1)) |
---|
1657 | printf(" (ignored)\n"); |
---|
1658 | return; |
---|
1659 | } |
---|
1660 | |
---|
1661 | /* |
---|
1662 | ** Check to see if this option can be specified by this user. |
---|
1663 | */ |
---|
1664 | |
---|
1665 | if (!safe && RealUid == 0) |
---|
1666 | safe = TRUE; |
---|
1667 | if (!safe && !o->o_safe) |
---|
1668 | { |
---|
1669 | if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) |
---|
1670 | { |
---|
1671 | if (tTd(37, 1)) |
---|
1672 | printf(" (unsafe)"); |
---|
1673 | (void) drop_privileges(TRUE); |
---|
1674 | } |
---|
1675 | } |
---|
1676 | if (tTd(37, 1)) |
---|
1677 | printf("\n"); |
---|
1678 | |
---|
1679 | switch (opt & 0xff) |
---|
1680 | { |
---|
1681 | case '7': /* force seven-bit input */ |
---|
1682 | SevenBitInput = atobool(val); |
---|
1683 | break; |
---|
1684 | |
---|
1685 | #if MIME8TO7 |
---|
1686 | case '8': /* handling of 8-bit input */ |
---|
1687 | switch (*val) |
---|
1688 | { |
---|
1689 | case 'm': /* convert 8-bit, convert MIME */ |
---|
1690 | MimeMode = MM_CVTMIME|MM_MIME8BIT; |
---|
1691 | break; |
---|
1692 | |
---|
1693 | case 'p': /* pass 8 bit, convert MIME */ |
---|
1694 | MimeMode = MM_CVTMIME|MM_PASS8BIT; |
---|
1695 | break; |
---|
1696 | |
---|
1697 | case 's': /* strict adherence */ |
---|
1698 | MimeMode = MM_CVTMIME; |
---|
1699 | break; |
---|
1700 | |
---|
1701 | #if 0 |
---|
1702 | case 'r': /* reject 8-bit, don't convert MIME */ |
---|
1703 | MimeMode = 0; |
---|
1704 | break; |
---|
1705 | |
---|
1706 | case 'j': /* "just send 8" */ |
---|
1707 | MimeMode = MM_PASS8BIT; |
---|
1708 | break; |
---|
1709 | |
---|
1710 | case 'a': /* encode 8 bit if available */ |
---|
1711 | MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; |
---|
1712 | break; |
---|
1713 | |
---|
1714 | case 'c': /* convert 8 bit to MIME, never 7 bit */ |
---|
1715 | MimeMode = MM_MIME8BIT; |
---|
1716 | break; |
---|
1717 | #endif |
---|
1718 | |
---|
1719 | default: |
---|
1720 | syserr("Unknown 8-bit mode %c", *val); |
---|
1721 | finis(FALSE, EX_USAGE); |
---|
1722 | } |
---|
1723 | break; |
---|
1724 | #endif |
---|
1725 | |
---|
1726 | case 'A': /* set default alias file */ |
---|
1727 | if (val[0] == '\0') |
---|
1728 | setalias("aliases"); |
---|
1729 | else |
---|
1730 | setalias(val); |
---|
1731 | break; |
---|
1732 | |
---|
1733 | case 'a': /* look N minutes for "@:@" in alias file */ |
---|
1734 | if (val[0] == '\0') |
---|
1735 | SafeAlias = 5 * 60; /* five minutes */ |
---|
1736 | else |
---|
1737 | SafeAlias = convtime(val, 'm'); |
---|
1738 | break; |
---|
1739 | |
---|
1740 | case 'B': /* substitution for blank character */ |
---|
1741 | SpaceSub = val[0]; |
---|
1742 | if (SpaceSub == '\0') |
---|
1743 | SpaceSub = ' '; |
---|
1744 | break; |
---|
1745 | |
---|
1746 | case 'b': /* min blocks free on queue fs/max msg size */ |
---|
1747 | p = strchr(val, '/'); |
---|
1748 | if (p != NULL) |
---|
1749 | { |
---|
1750 | *p++ = '\0'; |
---|
1751 | MaxMessageSize = atol(p); |
---|
1752 | } |
---|
1753 | MinBlocksFree = atol(val); |
---|
1754 | break; |
---|
1755 | |
---|
1756 | case 'c': /* don't connect to "expensive" mailers */ |
---|
1757 | NoConnect = atobool(val); |
---|
1758 | break; |
---|
1759 | |
---|
1760 | case 'C': /* checkpoint every N addresses */ |
---|
1761 | CheckpointInterval = atoi(val); |
---|
1762 | break; |
---|
1763 | |
---|
1764 | case 'd': /* delivery mode */ |
---|
1765 | switch (*val) |
---|
1766 | { |
---|
1767 | case '\0': |
---|
1768 | e->e_sendmode = SM_DELIVER; |
---|
1769 | break; |
---|
1770 | |
---|
1771 | case SM_QUEUE: /* queue only */ |
---|
1772 | case SM_DEFER: /* queue only and defer map lookups */ |
---|
1773 | #if !QUEUE |
---|
1774 | syserr("need QUEUE to set -odqueue or -oddefer"); |
---|
1775 | #endif /* QUEUE */ |
---|
1776 | /* fall through..... */ |
---|
1777 | |
---|
1778 | case SM_DELIVER: /* do everything */ |
---|
1779 | case SM_FORK: /* fork after verification */ |
---|
1780 | e->e_sendmode = *val; |
---|
1781 | break; |
---|
1782 | |
---|
1783 | default: |
---|
1784 | syserr("Unknown delivery mode %c", *val); |
---|
1785 | finis(FALSE, EX_USAGE); |
---|
1786 | } |
---|
1787 | buf[0] = (char)e->e_sendmode; |
---|
1788 | buf[1] = '\0'; |
---|
1789 | define(macid("{deliveryMode}", NULL), newstr(buf), e); |
---|
1790 | break; |
---|
1791 | |
---|
1792 | case 'D': /* rebuild alias database as needed */ |
---|
1793 | AutoRebuild = atobool(val); |
---|
1794 | break; |
---|
1795 | |
---|
1796 | case 'E': /* error message header/header file */ |
---|
1797 | if (*val != '\0') |
---|
1798 | ErrMsgFile = newstr(val); |
---|
1799 | break; |
---|
1800 | |
---|
1801 | case 'e': /* set error processing mode */ |
---|
1802 | switch (*val) |
---|
1803 | { |
---|
1804 | case EM_QUIET: /* be silent about it */ |
---|
1805 | case EM_MAIL: /* mail back */ |
---|
1806 | case EM_BERKNET: /* do berknet error processing */ |
---|
1807 | case EM_WRITE: /* write back (or mail) */ |
---|
1808 | case EM_PRINT: /* print errors normally (default) */ |
---|
1809 | e->e_errormode = *val; |
---|
1810 | break; |
---|
1811 | } |
---|
1812 | break; |
---|
1813 | |
---|
1814 | case 'F': /* file mode */ |
---|
1815 | FileMode = atooct(val) & 0777; |
---|
1816 | break; |
---|
1817 | |
---|
1818 | case 'f': /* save Unix-style From lines on front */ |
---|
1819 | SaveFrom = atobool(val); |
---|
1820 | break; |
---|
1821 | |
---|
1822 | case 'G': /* match recipients against GECOS field */ |
---|
1823 | MatchGecos = atobool(val); |
---|
1824 | break; |
---|
1825 | |
---|
1826 | case 'g': /* default gid */ |
---|
1827 | g_opt: |
---|
1828 | if (isascii(*val) && isdigit(*val)) |
---|
1829 | DefGid = atoi(val); |
---|
1830 | else |
---|
1831 | { |
---|
1832 | register struct group *gr; |
---|
1833 | |
---|
1834 | DefGid = -1; |
---|
1835 | gr = getgrnam(val); |
---|
1836 | if (gr == NULL) |
---|
1837 | syserr("readcf: option %c: unknown group %s", |
---|
1838 | opt, val); |
---|
1839 | else |
---|
1840 | DefGid = gr->gr_gid; |
---|
1841 | } |
---|
1842 | break; |
---|
1843 | |
---|
1844 | case 'H': /* help file */ |
---|
1845 | if (val[0] == '\0') |
---|
1846 | HelpFile = "sendmail.hf"; |
---|
1847 | else |
---|
1848 | HelpFile = newstr(val); |
---|
1849 | break; |
---|
1850 | |
---|
1851 | case 'h': /* maximum hop count */ |
---|
1852 | MaxHopCount = atoi(val); |
---|
1853 | break; |
---|
1854 | |
---|
1855 | case 'I': /* use internet domain name server */ |
---|
1856 | #if NAMED_BIND |
---|
1857 | for (p = val; *p != 0; ) |
---|
1858 | { |
---|
1859 | bool clearmode; |
---|
1860 | char *q; |
---|
1861 | struct resolverflags *rfp; |
---|
1862 | |
---|
1863 | while (*p == ' ') |
---|
1864 | p++; |
---|
1865 | if (*p == '\0') |
---|
1866 | break; |
---|
1867 | clearmode = FALSE; |
---|
1868 | if (*p == '-') |
---|
1869 | clearmode = TRUE; |
---|
1870 | else if (*p != '+') |
---|
1871 | p--; |
---|
1872 | p++; |
---|
1873 | q = p; |
---|
1874 | while (*p != '\0' && !(isascii(*p) && isspace(*p))) |
---|
1875 | p++; |
---|
1876 | if (*p != '\0') |
---|
1877 | *p++ = '\0'; |
---|
1878 | if (strcasecmp(q, "HasWildcardMX") == 0) |
---|
1879 | { |
---|
1880 | HasWildcardMX = !clearmode; |
---|
1881 | continue; |
---|
1882 | } |
---|
1883 | for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) |
---|
1884 | { |
---|
1885 | if (strcasecmp(q, rfp->rf_name) == 0) |
---|
1886 | break; |
---|
1887 | } |
---|
1888 | if (rfp->rf_name == NULL) |
---|
1889 | syserr("readcf: I option value %s unrecognized", q); |
---|
1890 | else if (clearmode) |
---|
1891 | _res.options &= ~rfp->rf_bits; |
---|
1892 | else |
---|
1893 | _res.options |= rfp->rf_bits; |
---|
1894 | } |
---|
1895 | if (tTd(8, 2)) |
---|
1896 | printf("_res.options = %x, HasWildcardMX = %d\n", |
---|
1897 | (u_int) _res.options, HasWildcardMX); |
---|
1898 | #else |
---|
1899 | usrerr("name server (I option) specified but BIND not compiled in"); |
---|
1900 | #endif |
---|
1901 | break; |
---|
1902 | |
---|
1903 | case 'i': /* ignore dot lines in message */ |
---|
1904 | IgnrDot = atobool(val); |
---|
1905 | break; |
---|
1906 | |
---|
1907 | case 'j': /* send errors in MIME (RFC 1341) format */ |
---|
1908 | SendMIMEErrors = atobool(val); |
---|
1909 | break; |
---|
1910 | |
---|
1911 | case 'J': /* .forward search path */ |
---|
1912 | ForwardPath = newstr(val); |
---|
1913 | break; |
---|
1914 | |
---|
1915 | case 'k': /* connection cache size */ |
---|
1916 | MaxMciCache = atoi(val); |
---|
1917 | if (MaxMciCache < 0) |
---|
1918 | MaxMciCache = 0; |
---|
1919 | break; |
---|
1920 | |
---|
1921 | case 'K': /* connection cache timeout */ |
---|
1922 | MciCacheTimeout = convtime(val, 'm'); |
---|
1923 | break; |
---|
1924 | |
---|
1925 | case 'l': /* use Errors-To: header */ |
---|
1926 | UseErrorsTo = atobool(val); |
---|
1927 | break; |
---|
1928 | |
---|
1929 | case 'L': /* log level */ |
---|
1930 | if (safe || LogLevel < atoi(val)) |
---|
1931 | LogLevel = atoi(val); |
---|
1932 | break; |
---|
1933 | |
---|
1934 | case 'M': /* define macro */ |
---|
1935 | mid = macid(val, &ep); |
---|
1936 | p = newstr(ep); |
---|
1937 | if (!safe) |
---|
1938 | cleanstrcpy(p, p, MAXNAME); |
---|
1939 | define(mid, p, CurEnv); |
---|
1940 | sticky = FALSE; |
---|
1941 | break; |
---|
1942 | |
---|
1943 | case 'm': /* send to me too */ |
---|
1944 | MeToo = atobool(val); |
---|
1945 | break; |
---|
1946 | |
---|
1947 | case 'n': /* validate RHS in newaliases */ |
---|
1948 | CheckAliases = atobool(val); |
---|
1949 | break; |
---|
1950 | |
---|
1951 | /* 'N' available -- was "net name" */ |
---|
1952 | |
---|
1953 | case 'O': /* daemon options */ |
---|
1954 | #if DAEMON |
---|
1955 | setdaemonoptions(val); |
---|
1956 | #else |
---|
1957 | syserr("DaemonPortOptions (O option) set but DAEMON not compiled in"); |
---|
1958 | #endif |
---|
1959 | break; |
---|
1960 | |
---|
1961 | case 'o': /* assume old style headers */ |
---|
1962 | if (atobool(val)) |
---|
1963 | CurEnv->e_flags |= EF_OLDSTYLE; |
---|
1964 | else |
---|
1965 | CurEnv->e_flags &= ~EF_OLDSTYLE; |
---|
1966 | break; |
---|
1967 | |
---|
1968 | case 'p': /* select privacy level */ |
---|
1969 | p = val; |
---|
1970 | for (;;) |
---|
1971 | { |
---|
1972 | register struct prival *pv; |
---|
1973 | extern struct prival PrivacyValues[]; |
---|
1974 | |
---|
1975 | while (isascii(*p) && (isspace(*p) || ispunct(*p))) |
---|
1976 | p++; |
---|
1977 | if (*p == '\0') |
---|
1978 | break; |
---|
1979 | val = p; |
---|
1980 | while (isascii(*p) && isalnum(*p)) |
---|
1981 | p++; |
---|
1982 | if (*p != '\0') |
---|
1983 | *p++ = '\0'; |
---|
1984 | |
---|
1985 | for (pv = PrivacyValues; pv->pv_name != NULL; pv++) |
---|
1986 | { |
---|
1987 | if (strcasecmp(val, pv->pv_name) == 0) |
---|
1988 | break; |
---|
1989 | } |
---|
1990 | if (pv->pv_name == NULL) |
---|
1991 | syserr("readcf: Op line: %s unrecognized", val); |
---|
1992 | PrivacyFlags |= pv->pv_flag; |
---|
1993 | } |
---|
1994 | sticky = FALSE; |
---|
1995 | break; |
---|
1996 | |
---|
1997 | case 'P': /* postmaster copy address for returned mail */ |
---|
1998 | PostMasterCopy = newstr(val); |
---|
1999 | break; |
---|
2000 | |
---|
2001 | case 'q': /* slope of queue only function */ |
---|
2002 | QueueFactor = atoi(val); |
---|
2003 | break; |
---|
2004 | |
---|
2005 | case 'Q': /* queue directory */ |
---|
2006 | if (val[0] == '\0') |
---|
2007 | QueueDir = "mqueue"; |
---|
2008 | else |
---|
2009 | QueueDir = newstr(val); |
---|
2010 | if (RealUid != 0 && !safe) |
---|
2011 | Warn_Q_option = TRUE; |
---|
2012 | break; |
---|
2013 | |
---|
2014 | case 'R': /* don't prune routes */ |
---|
2015 | DontPruneRoutes = atobool(val); |
---|
2016 | break; |
---|
2017 | |
---|
2018 | case 'r': /* read timeout */ |
---|
2019 | if (subopt == NULL) |
---|
2020 | inittimeouts(val); |
---|
2021 | else |
---|
2022 | settimeout(subopt, val); |
---|
2023 | break; |
---|
2024 | |
---|
2025 | case 'S': /* status file */ |
---|
2026 | if (val[0] == '\0') |
---|
2027 | StatFile = "sendmail.st"; |
---|
2028 | else |
---|
2029 | StatFile = newstr(val); |
---|
2030 | break; |
---|
2031 | |
---|
2032 | case 's': /* be super safe, even if expensive */ |
---|
2033 | SuperSafe = atobool(val); |
---|
2034 | break; |
---|
2035 | |
---|
2036 | case 'T': /* queue timeout */ |
---|
2037 | p = strchr(val, '/'); |
---|
2038 | if (p != NULL) |
---|
2039 | { |
---|
2040 | *p++ = '\0'; |
---|
2041 | settimeout("queuewarn", p); |
---|
2042 | } |
---|
2043 | settimeout("queuereturn", val); |
---|
2044 | break; |
---|
2045 | |
---|
2046 | case 't': /* time zone name */ |
---|
2047 | TimeZoneSpec = newstr(val); |
---|
2048 | break; |
---|
2049 | |
---|
2050 | case 'U': /* location of user database */ |
---|
2051 | UdbSpec = newstr(val); |
---|
2052 | break; |
---|
2053 | |
---|
2054 | case 'u': /* set default uid */ |
---|
2055 | for (p = val; *p != '\0'; p++) |
---|
2056 | { |
---|
2057 | if (*p == '.' || *p == '/' || *p == ':') |
---|
2058 | { |
---|
2059 | *p++ = '\0'; |
---|
2060 | break; |
---|
2061 | } |
---|
2062 | } |
---|
2063 | if (isascii(*val) && isdigit(*val)) |
---|
2064 | { |
---|
2065 | DefUid = atoi(val); |
---|
2066 | setdefuser(); |
---|
2067 | } |
---|
2068 | else |
---|
2069 | { |
---|
2070 | register struct passwd *pw; |
---|
2071 | |
---|
2072 | DefUid = -1; |
---|
2073 | pw = sm_getpwnam(val); |
---|
2074 | if (pw == NULL) |
---|
2075 | syserr("readcf: option u: unknown user %s", val); |
---|
2076 | else |
---|
2077 | { |
---|
2078 | DefUid = pw->pw_uid; |
---|
2079 | DefGid = pw->pw_gid; |
---|
2080 | DefUser = newstr(pw->pw_name); |
---|
2081 | } |
---|
2082 | } |
---|
2083 | |
---|
2084 | #ifdef UID_MAX |
---|
2085 | if (DefUid > UID_MAX) |
---|
2086 | { |
---|
2087 | syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored", |
---|
2088 | DefUid, UID_MAX); |
---|
2089 | } |
---|
2090 | #endif |
---|
2091 | |
---|
2092 | /* handle the group if it is there */ |
---|
2093 | if (*p == '\0') |
---|
2094 | break; |
---|
2095 | val = p; |
---|
2096 | goto g_opt; |
---|
2097 | |
---|
2098 | case 'V': /* fallback MX host */ |
---|
2099 | if (val[0] != '\0') |
---|
2100 | FallBackMX = newstr(val); |
---|
2101 | break; |
---|
2102 | |
---|
2103 | case 'v': /* run in verbose mode */ |
---|
2104 | Verbose = atobool(val) ? 1 : 0; |
---|
2105 | break; |
---|
2106 | |
---|
2107 | case 'w': /* if we are best MX, try host directly */ |
---|
2108 | TryNullMXList = atobool(val); |
---|
2109 | break; |
---|
2110 | |
---|
2111 | /* 'W' available -- was wizard password */ |
---|
2112 | |
---|
2113 | case 'x': /* load avg at which to auto-queue msgs */ |
---|
2114 | QueueLA = atoi(val); |
---|
2115 | break; |
---|
2116 | |
---|
2117 | case 'X': /* load avg at which to auto-reject connections */ |
---|
2118 | RefuseLA = atoi(val); |
---|
2119 | break; |
---|
2120 | |
---|
2121 | case 'y': /* work recipient factor */ |
---|
2122 | WkRecipFact = atoi(val); |
---|
2123 | break; |
---|
2124 | |
---|
2125 | case 'Y': /* fork jobs during queue runs */ |
---|
2126 | ForkQueueRuns = atobool(val); |
---|
2127 | break; |
---|
2128 | |
---|
2129 | case 'z': /* work message class factor */ |
---|
2130 | WkClassFact = atoi(val); |
---|
2131 | break; |
---|
2132 | |
---|
2133 | case 'Z': /* work time factor */ |
---|
2134 | WkTimeFact = atoi(val); |
---|
2135 | break; |
---|
2136 | |
---|
2137 | case O_QUEUESORTORD: /* queue sorting order */ |
---|
2138 | switch (*val) |
---|
2139 | { |
---|
2140 | case 'h': /* Host first */ |
---|
2141 | case 'H': |
---|
2142 | QueueSortOrder = QS_BYHOST; |
---|
2143 | break; |
---|
2144 | |
---|
2145 | case 'p': /* Priority order */ |
---|
2146 | case 'P': |
---|
2147 | QueueSortOrder = QS_BYPRIORITY; |
---|
2148 | break; |
---|
2149 | |
---|
2150 | case 't': /* Submission time */ |
---|
2151 | case 'T': |
---|
2152 | QueueSortOrder = QS_BYTIME; |
---|
2153 | break; |
---|
2154 | |
---|
2155 | default: |
---|
2156 | syserr("Invalid queue sort order \"%s\"", val); |
---|
2157 | } |
---|
2158 | break; |
---|
2159 | |
---|
2160 | case O_HOSTSFILE: /* pathname of /etc/hosts file */ |
---|
2161 | HostsFile = newstr(val); |
---|
2162 | break; |
---|
2163 | |
---|
2164 | case O_MQA: /* minimum queue age between deliveries */ |
---|
2165 | MinQueueAge = convtime(val, 'm'); |
---|
2166 | break; |
---|
2167 | |
---|
2168 | case O_DEFCHARSET: /* default character set for mimefying */ |
---|
2169 | DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); |
---|
2170 | break; |
---|
2171 | |
---|
2172 | case O_SSFILE: /* service switch file */ |
---|
2173 | ServiceSwitchFile = newstr(val); |
---|
2174 | break; |
---|
2175 | |
---|
2176 | case O_DIALDELAY: /* delay for dial-on-demand operation */ |
---|
2177 | DialDelay = convtime(val, 's'); |
---|
2178 | break; |
---|
2179 | |
---|
2180 | case O_NORCPTACTION: /* what to do if no recipient */ |
---|
2181 | if (strcasecmp(val, "none") == 0) |
---|
2182 | NoRecipientAction = NRA_NO_ACTION; |
---|
2183 | else if (strcasecmp(val, "add-to") == 0) |
---|
2184 | NoRecipientAction = NRA_ADD_TO; |
---|
2185 | else if (strcasecmp(val, "add-apparently-to") == 0) |
---|
2186 | NoRecipientAction = NRA_ADD_APPARENTLY_TO; |
---|
2187 | else if (strcasecmp(val, "add-bcc") == 0) |
---|
2188 | NoRecipientAction = NRA_ADD_BCC; |
---|
2189 | else if (strcasecmp(val, "add-to-undisclosed") == 0) |
---|
2190 | NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; |
---|
2191 | else |
---|
2192 | syserr("Invalid NoRecipientAction: %s", val); |
---|
2193 | break; |
---|
2194 | |
---|
2195 | case O_SAFEFILEENV: /* chroot() environ for writing to files */ |
---|
2196 | SafeFileEnv = newstr(val); |
---|
2197 | break; |
---|
2198 | |
---|
2199 | case O_MAXMSGSIZE: /* maximum message size */ |
---|
2200 | MaxMessageSize = atol(val); |
---|
2201 | break; |
---|
2202 | |
---|
2203 | case O_COLONOKINADDR: /* old style handling of colon addresses */ |
---|
2204 | ColonOkInAddr = atobool(val); |
---|
2205 | break; |
---|
2206 | |
---|
2207 | case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ |
---|
2208 | MaxQueueRun = atol(val); |
---|
2209 | break; |
---|
2210 | |
---|
2211 | case O_MAXCHILDREN: /* max # of children of daemon */ |
---|
2212 | MaxChildren = atoi(val); |
---|
2213 | break; |
---|
2214 | |
---|
2215 | case O_KEEPCNAMES: /* don't expand CNAME records */ |
---|
2216 | DontExpandCnames = atobool(val); |
---|
2217 | break; |
---|
2218 | |
---|
2219 | case O_MUSTQUOTE: /* must quote these characters in phrases */ |
---|
2220 | strcpy(buf, "@,;:\\()[]"); |
---|
2221 | if (strlen(val) < (SIZE_T) sizeof buf - 10) |
---|
2222 | strcat(buf, val); |
---|
2223 | MustQuoteChars = newstr(buf); |
---|
2224 | break; |
---|
2225 | |
---|
2226 | case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */ |
---|
2227 | SmtpGreeting = newstr(munchstring(val, NULL, '\0')); |
---|
2228 | break; |
---|
2229 | |
---|
2230 | case O_UNIXFROM: /* UNIX From_ line (old $l macro) */ |
---|
2231 | UnixFromLine = newstr(munchstring(val, NULL, '\0')); |
---|
2232 | break; |
---|
2233 | |
---|
2234 | case O_OPCHARS: /* operator characters (old $o macro) */ |
---|
2235 | OperatorChars = newstr(munchstring(val, NULL, '\0')); |
---|
2236 | break; |
---|
2237 | |
---|
2238 | case O_DONTINITGRPS: /* don't call initgroups(3) */ |
---|
2239 | DontInitGroups = atobool(val); |
---|
2240 | break; |
---|
2241 | |
---|
2242 | case O_SLFH: /* make sure from fits on one line */ |
---|
2243 | SingleLineFromHeader = atobool(val); |
---|
2244 | break; |
---|
2245 | |
---|
2246 | case O_ABH: /* allow HELO commands with syntax errors */ |
---|
2247 | AllowBogusHELO = atobool(val); |
---|
2248 | break; |
---|
2249 | |
---|
2250 | case O_CONNTHROT: /* connection rate throttle */ |
---|
2251 | ConnRateThrottle = atoi(val); |
---|
2252 | break; |
---|
2253 | |
---|
2254 | case O_UGW: /* group writable files are unsafe */ |
---|
2255 | if (!atobool(val)) |
---|
2256 | DontBlameSendmail |= DBS_GROUPWRITABLEFORWARDFILESAFE|DBS_GROUPWRITABLEINCLUDEFILESAFE; |
---|
2257 | break; |
---|
2258 | |
---|
2259 | case O_DBLBOUNCE: /* address to which to send double bounces */ |
---|
2260 | if (val[0] != '\0') |
---|
2261 | DoubleBounceAddr = newstr(val); |
---|
2262 | else |
---|
2263 | syserr("readcf: option DoubleBounceAddress: value required"); |
---|
2264 | break; |
---|
2265 | |
---|
2266 | case O_HSDIR: /* persistent host status directory */ |
---|
2267 | if (val[0] != '\0') |
---|
2268 | HostStatDir = newstr(val); |
---|
2269 | break; |
---|
2270 | |
---|
2271 | case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */ |
---|
2272 | SingleThreadDelivery = atobool(val); |
---|
2273 | break; |
---|
2274 | |
---|
2275 | case O_RUNASUSER: /* run bulk of code as this user */ |
---|
2276 | for (p = val; *p != '\0'; p++) |
---|
2277 | { |
---|
2278 | if (*p == '.' || *p == '/' || *p == ':') |
---|
2279 | { |
---|
2280 | *p++ = '\0'; |
---|
2281 | break; |
---|
2282 | } |
---|
2283 | } |
---|
2284 | if (isascii(*val) && isdigit(*val)) |
---|
2285 | { |
---|
2286 | if (can_setuid) |
---|
2287 | RunAsUid = atoi(val); |
---|
2288 | } |
---|
2289 | else |
---|
2290 | { |
---|
2291 | register struct passwd *pw; |
---|
2292 | |
---|
2293 | pw = sm_getpwnam(val); |
---|
2294 | if (pw == NULL) |
---|
2295 | syserr("readcf: option RunAsUser: unknown user %s", val); |
---|
2296 | else if (can_setuid) |
---|
2297 | { |
---|
2298 | if (*p == '\0') |
---|
2299 | RunAsUserName = newstr(val); |
---|
2300 | RunAsUid = pw->pw_uid; |
---|
2301 | RunAsGid = pw->pw_gid; |
---|
2302 | } |
---|
2303 | } |
---|
2304 | #ifdef UID_MAX |
---|
2305 | if (RunAsUid > UID_MAX) |
---|
2306 | { |
---|
2307 | syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored", |
---|
2308 | RunAsUid, UID_MAX); |
---|
2309 | } |
---|
2310 | #endif |
---|
2311 | if (*p != '\0') |
---|
2312 | { |
---|
2313 | if (isascii(*p) && isdigit(*p)) |
---|
2314 | { |
---|
2315 | if (can_setuid) |
---|
2316 | RunAsGid = atoi(p); |
---|
2317 | } |
---|
2318 | else |
---|
2319 | { |
---|
2320 | register struct group *gr; |
---|
2321 | |
---|
2322 | gr = getgrnam(p); |
---|
2323 | if (gr == NULL) |
---|
2324 | syserr("readcf: option RunAsUser: unknown group %s", |
---|
2325 | p); |
---|
2326 | else if (can_setuid) |
---|
2327 | RunAsGid = gr->gr_gid; |
---|
2328 | } |
---|
2329 | } |
---|
2330 | if (tTd(47, 5)) |
---|
2331 | printf("readcf: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid); |
---|
2332 | break; |
---|
2333 | |
---|
2334 | #if _FFR_DSN_RRT_OPTION |
---|
2335 | case O_DSN_RRT: |
---|
2336 | RrtImpliesDsn = atobool(val); |
---|
2337 | break; |
---|
2338 | #endif |
---|
2339 | |
---|
2340 | #if _FFR_PIDFILE_OPTION |
---|
2341 | case O_PIDFILE: |
---|
2342 | free(PidFile); |
---|
2343 | PidFile = newstr(val); |
---|
2344 | break; |
---|
2345 | #endif |
---|
2346 | |
---|
2347 | case O_DONTBLAMESENDMAIL: |
---|
2348 | p = val; |
---|
2349 | for (;;) |
---|
2350 | { |
---|
2351 | register struct dbsval *dbs; |
---|
2352 | extern struct dbsval DontBlameSendmailValues[]; |
---|
2353 | |
---|
2354 | while (isascii(*p) && (isspace(*p) || ispunct(*p))) |
---|
2355 | p++; |
---|
2356 | if (*p == '\0') |
---|
2357 | break; |
---|
2358 | val = p; |
---|
2359 | while (isascii(*p) && isalnum(*p)) |
---|
2360 | p++; |
---|
2361 | if (*p != '\0') |
---|
2362 | *p++ = '\0'; |
---|
2363 | |
---|
2364 | for (dbs = DontBlameSendmailValues; |
---|
2365 | dbs->dbs_name != NULL; dbs++) |
---|
2366 | { |
---|
2367 | if (strcasecmp(val, dbs->dbs_name) == 0) |
---|
2368 | break; |
---|
2369 | } |
---|
2370 | if (dbs->dbs_name == NULL) |
---|
2371 | syserr("readcf: DontBlameSendmail option: %s unrecognized", val); |
---|
2372 | else if (dbs->dbs_flag == DBS_SAFE) |
---|
2373 | DontBlameSendmail = DBS_SAFE; |
---|
2374 | else |
---|
2375 | DontBlameSendmail |= dbs->dbs_flag; |
---|
2376 | } |
---|
2377 | sticky = FALSE; |
---|
2378 | break; |
---|
2379 | |
---|
2380 | case O_DPI: |
---|
2381 | DontProbeInterfaces = atobool(val); |
---|
2382 | break; |
---|
2383 | |
---|
2384 | case O_MAXRCPT: |
---|
2385 | MaxRcptPerMsg = atoi(val); |
---|
2386 | break; |
---|
2387 | |
---|
2388 | #if _FFR_DEADLETTERDROP_OPTION |
---|
2389 | case O_DEADLETTER: |
---|
2390 | if (DeadLetterDrop != NULL) |
---|
2391 | free(DeadLetterDrop); |
---|
2392 | DeadLetterDrop = newstr(val); |
---|
2393 | break; |
---|
2394 | #endif |
---|
2395 | |
---|
2396 | #if _FFR_DONTLOCKFILESFORREAD_OPTION |
---|
2397 | case O_DONTLOCK: |
---|
2398 | DontLockReadFiles = atobool(val); |
---|
2399 | break; |
---|
2400 | #endif |
---|
2401 | |
---|
2402 | #if _FFR_MAXALIASRECURSION_OPTION |
---|
2403 | case O_MAXALIASRCSN: |
---|
2404 | MaxAliasRecursion = atoi(val); |
---|
2405 | break; |
---|
2406 | #endif |
---|
2407 | |
---|
2408 | #if _FFR_CONNECTONLYTO_OPTION |
---|
2409 | case O_CNCTONLYTO: |
---|
2410 | /* XXX should probably use gethostbyname */ |
---|
2411 | ConnectOnlyTo = inet_addr(val); |
---|
2412 | break; |
---|
2413 | #endif |
---|
2414 | |
---|
2415 | #if _FFR_TRUSTED_USER |
---|
2416 | case O_TRUSTUSER: |
---|
2417 | if (isascii(*val) && isdigit(*val)) |
---|
2418 | TrustedUid = atoi(val); |
---|
2419 | else |
---|
2420 | { |
---|
2421 | register struct passwd *pw; |
---|
2422 | |
---|
2423 | TrustedUid = 0; |
---|
2424 | pw = sm_getpwnam(val); |
---|
2425 | if (pw == NULL) |
---|
2426 | syserr("readcf: option TrustedUser: unknown user %s", val); |
---|
2427 | else |
---|
2428 | TrustedUid = pw->pw_uid; |
---|
2429 | } |
---|
2430 | |
---|
2431 | #ifdef UID_MAX |
---|
2432 | if (TrustedUid > UID_MAX) |
---|
2433 | { |
---|
2434 | syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)", |
---|
2435 | TrustedUid, UID_MAX); |
---|
2436 | TrustedUid = 0; |
---|
2437 | } |
---|
2438 | #endif |
---|
2439 | break; |
---|
2440 | #endif |
---|
2441 | |
---|
2442 | #if _FFR_MAX_MIME_HEADER_LENGTH |
---|
2443 | case O_MAXMIMEHDRLEN: |
---|
2444 | p = strchr(val, '/'); |
---|
2445 | if (p != NULL) |
---|
2446 | *p++ = '\0'; |
---|
2447 | MaxMimeHeaderLength = atoi(val); |
---|
2448 | if (p != NULL && *p != '\0') |
---|
2449 | MaxMimeFieldLength = atoi(p); |
---|
2450 | else |
---|
2451 | MaxMimeFieldLength = MaxMimeHeaderLength / 2; |
---|
2452 | |
---|
2453 | if (MaxMimeHeaderLength < 0) |
---|
2454 | MaxMimeHeaderLength = 0; |
---|
2455 | else if (MaxMimeHeaderLength < 128) |
---|
2456 | printf("Warning: MaxMimeHeaderLength: header length limit set lower than 128\n"); |
---|
2457 | |
---|
2458 | if (MaxMimeFieldLength < 0) |
---|
2459 | MaxMimeFieldLength = 0; |
---|
2460 | else if (MaxMimeFieldLength < 40) |
---|
2461 | printf("Warning: MaxMimeHeaderLength: field length limit set lower than 40\n"); |
---|
2462 | break; |
---|
2463 | #endif |
---|
2464 | |
---|
2465 | #if _FFR_CONTROL_SOCKET |
---|
2466 | case O_CONTROLSOCKET: |
---|
2467 | if (ControlSocketName != NULL) |
---|
2468 | free(ControlSocketName); |
---|
2469 | ControlSocketName = newstr(val); |
---|
2470 | break; |
---|
2471 | #endif |
---|
2472 | |
---|
2473 | #if _FFR_MAX_HEADERS_LENGTH |
---|
2474 | case O_MAXHDRSLEN: |
---|
2475 | MaxHeadersLength = atoi(val); |
---|
2476 | |
---|
2477 | if (MaxHeadersLength > 0 && |
---|
2478 | MaxHeadersLength < (MAXHDRSLEN / 2)) |
---|
2479 | printf("Warning: MaxHeadersLength: headers length limit set lower than %d\n", MAXHDRSLEN); |
---|
2480 | break; |
---|
2481 | #endif |
---|
2482 | |
---|
2483 | default: |
---|
2484 | if (tTd(37, 1)) |
---|
2485 | { |
---|
2486 | if (isascii(opt) && isprint(opt)) |
---|
2487 | printf("Warning: option %c unknown\n", opt); |
---|
2488 | else |
---|
2489 | printf("Warning: option 0x%x unknown\n", opt); |
---|
2490 | } |
---|
2491 | break; |
---|
2492 | } |
---|
2493 | if (sticky) |
---|
2494 | setbitn(opt, StickyOpt); |
---|
2495 | } |
---|
2496 | /* |
---|
2497 | ** SETCLASS -- set a string into a class |
---|
2498 | ** |
---|
2499 | ** Parameters: |
---|
2500 | ** class -- the class to put the string in. |
---|
2501 | ** str -- the string to enter |
---|
2502 | ** |
---|
2503 | ** Returns: |
---|
2504 | ** none. |
---|
2505 | ** |
---|
2506 | ** Side Effects: |
---|
2507 | ** puts the word into the symbol table. |
---|
2508 | */ |
---|
2509 | |
---|
2510 | void |
---|
2511 | setclass(class, str) |
---|
2512 | int class; |
---|
2513 | char *str; |
---|
2514 | { |
---|
2515 | register STAB *s; |
---|
2516 | |
---|
2517 | if (tTd(37, 8)) |
---|
2518 | printf("setclass(%s, %s)\n", macname(class), str); |
---|
2519 | s = stab(str, ST_CLASS, ST_ENTER); |
---|
2520 | setbitn(class, s->s_class); |
---|
2521 | } |
---|
2522 | /* |
---|
2523 | ** MAKEMAPENTRY -- create a map entry |
---|
2524 | ** |
---|
2525 | ** Parameters: |
---|
2526 | ** line -- the config file line |
---|
2527 | ** |
---|
2528 | ** Returns: |
---|
2529 | ** A pointer to the map that has been created. |
---|
2530 | ** NULL if there was a syntax error. |
---|
2531 | ** |
---|
2532 | ** Side Effects: |
---|
2533 | ** Enters the map into the dictionary. |
---|
2534 | */ |
---|
2535 | |
---|
2536 | MAP * |
---|
2537 | makemapentry(line) |
---|
2538 | char *line; |
---|
2539 | { |
---|
2540 | register char *p; |
---|
2541 | char *mapname; |
---|
2542 | char *classname; |
---|
2543 | register STAB *s; |
---|
2544 | STAB *class; |
---|
2545 | |
---|
2546 | for (p = line; isascii(*p) && isspace(*p); p++) |
---|
2547 | continue; |
---|
2548 | if (!(isascii(*p) && isalnum(*p))) |
---|
2549 | { |
---|
2550 | syserr("readcf: config K line: no map name"); |
---|
2551 | return NULL; |
---|
2552 | } |
---|
2553 | |
---|
2554 | mapname = p; |
---|
2555 | while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.') |
---|
2556 | continue; |
---|
2557 | if (*p != '\0') |
---|
2558 | *p++ = '\0'; |
---|
2559 | while (isascii(*p) && isspace(*p)) |
---|
2560 | p++; |
---|
2561 | if (!(isascii(*p) && isalnum(*p))) |
---|
2562 | { |
---|
2563 | syserr("readcf: config K line, map %s: no map class", mapname); |
---|
2564 | return NULL; |
---|
2565 | } |
---|
2566 | classname = p; |
---|
2567 | while (isascii(*++p) && isalnum(*p)) |
---|
2568 | continue; |
---|
2569 | if (*p != '\0') |
---|
2570 | *p++ = '\0'; |
---|
2571 | while (isascii(*p) && isspace(*p)) |
---|
2572 | p++; |
---|
2573 | |
---|
2574 | /* look up the class */ |
---|
2575 | class = stab(classname, ST_MAPCLASS, ST_FIND); |
---|
2576 | if (class == NULL) |
---|
2577 | { |
---|
2578 | syserr("readcf: map %s: class %s not available", mapname, classname); |
---|
2579 | return NULL; |
---|
2580 | } |
---|
2581 | |
---|
2582 | /* enter the map */ |
---|
2583 | s = stab(mapname, ST_MAP, ST_ENTER); |
---|
2584 | s->s_map.map_class = &class->s_mapclass; |
---|
2585 | s->s_map.map_mname = newstr(mapname); |
---|
2586 | |
---|
2587 | if (class->s_mapclass.map_parse(&s->s_map, p)) |
---|
2588 | s->s_map.map_mflags |= MF_VALID; |
---|
2589 | |
---|
2590 | if (tTd(37, 5)) |
---|
2591 | { |
---|
2592 | printf("map %s, class %s, flags %lx, file %s,\n", |
---|
2593 | s->s_map.map_mname, s->s_map.map_class->map_cname, |
---|
2594 | s->s_map.map_mflags, |
---|
2595 | s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); |
---|
2596 | printf("\tapp %s, domain %s, rebuild %s\n", |
---|
2597 | s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, |
---|
2598 | s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, |
---|
2599 | s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); |
---|
2600 | } |
---|
2601 | |
---|
2602 | return &s->s_map; |
---|
2603 | } |
---|
2604 | /* |
---|
2605 | ** STRTORWSET -- convert string to rewriting set number |
---|
2606 | ** |
---|
2607 | ** Parameters: |
---|
2608 | ** p -- the pointer to the string to decode. |
---|
2609 | ** endp -- if set, store the trailing delimiter here. |
---|
2610 | ** stabmode -- ST_ENTER to create this entry, ST_FIND if |
---|
2611 | ** it must already exist. |
---|
2612 | ** |
---|
2613 | ** Returns: |
---|
2614 | ** The appropriate ruleset number. |
---|
2615 | ** -1 if it is not valid (error already printed) |
---|
2616 | */ |
---|
2617 | |
---|
2618 | int |
---|
2619 | strtorwset(p, endp, stabmode) |
---|
2620 | char *p; |
---|
2621 | char **endp; |
---|
2622 | int stabmode; |
---|
2623 | { |
---|
2624 | int ruleset; |
---|
2625 | static int nextruleset = MAXRWSETS; |
---|
2626 | |
---|
2627 | while (isascii(*p) && isspace(*p)) |
---|
2628 | p++; |
---|
2629 | if (!isascii(*p)) |
---|
2630 | { |
---|
2631 | syserr("invalid ruleset name: \"%.20s\"", p); |
---|
2632 | return -1; |
---|
2633 | } |
---|
2634 | if (isdigit(*p)) |
---|
2635 | { |
---|
2636 | ruleset = strtol(p, endp, 10); |
---|
2637 | if (ruleset >= MAXRWSETS / 2 || ruleset < 0) |
---|
2638 | { |
---|
2639 | syserr("bad ruleset %d (%d max)", |
---|
2640 | ruleset, MAXRWSETS / 2); |
---|
2641 | ruleset = -1; |
---|
2642 | } |
---|
2643 | } |
---|
2644 | else |
---|
2645 | { |
---|
2646 | STAB *s; |
---|
2647 | char delim; |
---|
2648 | char *q; |
---|
2649 | |
---|
2650 | q = p; |
---|
2651 | while (*p != '\0' && isascii(*p) && |
---|
2652 | (isalnum(*p) || *p == '_')) |
---|
2653 | p++; |
---|
2654 | if (q == p || !(isascii(*q) && isalpha(*q))) |
---|
2655 | { |
---|
2656 | /* no valid characters */ |
---|
2657 | syserr("invalid ruleset name: \"%.20s\"", q); |
---|
2658 | return -1; |
---|
2659 | } |
---|
2660 | while (isascii(*p) && isspace(*p)) |
---|
2661 | *p++ = '\0'; |
---|
2662 | delim = *p; |
---|
2663 | if (delim != '\0') |
---|
2664 | *p = '\0'; |
---|
2665 | s = stab(q, ST_RULESET, stabmode); |
---|
2666 | if (delim != '\0') |
---|
2667 | *p = delim; |
---|
2668 | |
---|
2669 | if (s == NULL) |
---|
2670 | return -1; |
---|
2671 | |
---|
2672 | if (stabmode == ST_ENTER && delim == '=') |
---|
2673 | { |
---|
2674 | while (isascii(*++p) && isspace(*p)) |
---|
2675 | continue; |
---|
2676 | if (!(isascii(*p) && isdigit(*p))) |
---|
2677 | { |
---|
2678 | syserr("bad ruleset definition \"%s\" (number required after `=')", q); |
---|
2679 | ruleset = -1; |
---|
2680 | } |
---|
2681 | else |
---|
2682 | { |
---|
2683 | ruleset = strtol(p, endp, 10); |
---|
2684 | if (ruleset >= MAXRWSETS / 2 || ruleset < 0) |
---|
2685 | { |
---|
2686 | syserr("bad ruleset number %d in \"%s\" (%d max)", |
---|
2687 | ruleset, q, MAXRWSETS / 2); |
---|
2688 | ruleset = -1; |
---|
2689 | } |
---|
2690 | } |
---|
2691 | } |
---|
2692 | else |
---|
2693 | { |
---|
2694 | if (endp != NULL) |
---|
2695 | *endp = p; |
---|
2696 | if (s->s_ruleset > 0) |
---|
2697 | ruleset = s->s_ruleset; |
---|
2698 | else if ((ruleset = --nextruleset) < MAXRWSETS / 2) |
---|
2699 | { |
---|
2700 | syserr("%s: too many named rulesets (%d max)", |
---|
2701 | q, MAXRWSETS / 2); |
---|
2702 | ruleset = -1; |
---|
2703 | } |
---|
2704 | } |
---|
2705 | if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) |
---|
2706 | { |
---|
2707 | syserr("%s: ruleset changed value (old %d, new %d)", |
---|
2708 | q, s->s_ruleset, ruleset); |
---|
2709 | ruleset = s->s_ruleset; |
---|
2710 | } |
---|
2711 | else if (ruleset > 0) |
---|
2712 | { |
---|
2713 | s->s_ruleset = ruleset; |
---|
2714 | } |
---|
2715 | } |
---|
2716 | return ruleset; |
---|
2717 | } |
---|
2718 | /* |
---|
2719 | ** INITTIMEOUTS -- parse and set timeout values |
---|
2720 | ** |
---|
2721 | ** Parameters: |
---|
2722 | ** val -- a pointer to the values. If NULL, do initial |
---|
2723 | ** settings. |
---|
2724 | ** |
---|
2725 | ** Returns: |
---|
2726 | ** none. |
---|
2727 | ** |
---|
2728 | ** Side Effects: |
---|
2729 | ** Initializes the TimeOuts structure |
---|
2730 | */ |
---|
2731 | |
---|
2732 | #define SECONDS |
---|
2733 | #define MINUTES * 60 |
---|
2734 | #define HOUR * 3600 |
---|
2735 | |
---|
2736 | void |
---|
2737 | inittimeouts(val) |
---|
2738 | register char *val; |
---|
2739 | { |
---|
2740 | register char *p; |
---|
2741 | extern time_t convtime __P((char *, char)); |
---|
2742 | |
---|
2743 | if (tTd(37, 2)) |
---|
2744 | printf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val); |
---|
2745 | if (val == NULL) |
---|
2746 | { |
---|
2747 | TimeOuts.to_connect = (time_t) 0 SECONDS; |
---|
2748 | TimeOuts.to_initial = (time_t) 5 MINUTES; |
---|
2749 | TimeOuts.to_helo = (time_t) 5 MINUTES; |
---|
2750 | TimeOuts.to_mail = (time_t) 10 MINUTES; |
---|
2751 | TimeOuts.to_rcpt = (time_t) 1 HOUR; |
---|
2752 | TimeOuts.to_datainit = (time_t) 5 MINUTES; |
---|
2753 | TimeOuts.to_datablock = (time_t) 1 HOUR; |
---|
2754 | TimeOuts.to_datafinal = (time_t) 1 HOUR; |
---|
2755 | TimeOuts.to_rset = (time_t) 5 MINUTES; |
---|
2756 | TimeOuts.to_quit = (time_t) 2 MINUTES; |
---|
2757 | TimeOuts.to_nextcommand = (time_t) 1 HOUR; |
---|
2758 | TimeOuts.to_miscshort = (time_t) 2 MINUTES; |
---|
2759 | #if IDENTPROTO |
---|
2760 | TimeOuts.to_ident = (time_t) 30 SECONDS; |
---|
2761 | #else |
---|
2762 | TimeOuts.to_ident = (time_t) 0 SECONDS; |
---|
2763 | #endif |
---|
2764 | TimeOuts.to_fileopen = (time_t) 60 SECONDS; |
---|
2765 | if (tTd(37, 5)) |
---|
2766 | { |
---|
2767 | printf("Timeouts:\n"); |
---|
2768 | printf(" connect = %ld\n", (long)TimeOuts.to_connect); |
---|
2769 | printf(" initial = %ld\n", (long)TimeOuts.to_initial); |
---|
2770 | printf(" helo = %ld\n", (long)TimeOuts.to_helo); |
---|
2771 | printf(" mail = %ld\n", (long)TimeOuts.to_mail); |
---|
2772 | printf(" rcpt = %ld\n", (long)TimeOuts.to_rcpt); |
---|
2773 | printf(" datainit = %ld\n", (long)TimeOuts.to_datainit); |
---|
2774 | printf(" datablock = %ld\n", (long)TimeOuts.to_datablock); |
---|
2775 | printf(" datafinal = %ld\n", (long)TimeOuts.to_datafinal); |
---|
2776 | printf(" rset = %ld\n", (long)TimeOuts.to_rset); |
---|
2777 | printf(" quit = %ld\n", (long)TimeOuts.to_quit); |
---|
2778 | printf(" nextcommand = %ld\n", (long)TimeOuts.to_nextcommand); |
---|
2779 | printf(" miscshort = %ld\n", (long)TimeOuts.to_miscshort); |
---|
2780 | printf(" ident = %ld\n", (long)TimeOuts.to_ident); |
---|
2781 | printf(" fileopen = %ld\n", (long)TimeOuts.to_fileopen); |
---|
2782 | } |
---|
2783 | return; |
---|
2784 | } |
---|
2785 | |
---|
2786 | for (;; val = p) |
---|
2787 | { |
---|
2788 | while (isascii(*val) && isspace(*val)) |
---|
2789 | val++; |
---|
2790 | if (*val == '\0') |
---|
2791 | break; |
---|
2792 | for (p = val; *p != '\0' && *p != ','; p++) |
---|
2793 | continue; |
---|
2794 | if (*p != '\0') |
---|
2795 | *p++ = '\0'; |
---|
2796 | |
---|
2797 | if (isascii(*val) && isdigit(*val)) |
---|
2798 | { |
---|
2799 | /* old syntax -- set everything */ |
---|
2800 | TimeOuts.to_mail = convtime(val, 'm'); |
---|
2801 | TimeOuts.to_rcpt = TimeOuts.to_mail; |
---|
2802 | TimeOuts.to_datainit = TimeOuts.to_mail; |
---|
2803 | TimeOuts.to_datablock = TimeOuts.to_mail; |
---|
2804 | TimeOuts.to_datafinal = TimeOuts.to_mail; |
---|
2805 | TimeOuts.to_nextcommand = TimeOuts.to_mail; |
---|
2806 | continue; |
---|
2807 | } |
---|
2808 | else |
---|
2809 | { |
---|
2810 | register char *q = strchr(val, ':'); |
---|
2811 | |
---|
2812 | if (q == NULL && (q = strchr(val, '=')) == NULL) |
---|
2813 | { |
---|
2814 | /* syntax error */ |
---|
2815 | continue; |
---|
2816 | } |
---|
2817 | *q++ = '\0'; |
---|
2818 | settimeout(val, q); |
---|
2819 | } |
---|
2820 | } |
---|
2821 | } |
---|
2822 | /* |
---|
2823 | ** SETTIMEOUT -- set an individual timeout |
---|
2824 | ** |
---|
2825 | ** Parameters: |
---|
2826 | ** name -- the name of the timeout. |
---|
2827 | ** val -- the value of the timeout. |
---|
2828 | ** |
---|
2829 | ** Returns: |
---|
2830 | ** none. |
---|
2831 | */ |
---|
2832 | |
---|
2833 | void |
---|
2834 | settimeout(name, val) |
---|
2835 | char *name; |
---|
2836 | char *val; |
---|
2837 | { |
---|
2838 | register char *p; |
---|
2839 | time_t to; |
---|
2840 | extern time_t convtime __P((char *, char)); |
---|
2841 | |
---|
2842 | if (tTd(37, 2)) |
---|
2843 | printf("settimeout(%s = %s)\n", name, val); |
---|
2844 | |
---|
2845 | to = convtime(val, 'm'); |
---|
2846 | p = strchr(name, '.'); |
---|
2847 | if (p != NULL) |
---|
2848 | *p++ = '\0'; |
---|
2849 | |
---|
2850 | if (strcasecmp(name, "initial") == 0) |
---|
2851 | TimeOuts.to_initial = to; |
---|
2852 | else if (strcasecmp(name, "mail") == 0) |
---|
2853 | TimeOuts.to_mail = to; |
---|
2854 | else if (strcasecmp(name, "rcpt") == 0) |
---|
2855 | TimeOuts.to_rcpt = to; |
---|
2856 | else if (strcasecmp(name, "datainit") == 0) |
---|
2857 | TimeOuts.to_datainit = to; |
---|
2858 | else if (strcasecmp(name, "datablock") == 0) |
---|
2859 | TimeOuts.to_datablock = to; |
---|
2860 | else if (strcasecmp(name, "datafinal") == 0) |
---|
2861 | TimeOuts.to_datafinal = to; |
---|
2862 | else if (strcasecmp(name, "command") == 0) |
---|
2863 | TimeOuts.to_nextcommand = to; |
---|
2864 | else if (strcasecmp(name, "rset") == 0) |
---|
2865 | TimeOuts.to_rset = to; |
---|
2866 | else if (strcasecmp(name, "helo") == 0) |
---|
2867 | TimeOuts.to_helo = to; |
---|
2868 | else if (strcasecmp(name, "quit") == 0) |
---|
2869 | TimeOuts.to_quit = to; |
---|
2870 | else if (strcasecmp(name, "misc") == 0) |
---|
2871 | TimeOuts.to_miscshort = to; |
---|
2872 | else if (strcasecmp(name, "ident") == 0) |
---|
2873 | TimeOuts.to_ident = to; |
---|
2874 | else if (strcasecmp(name, "fileopen") == 0) |
---|
2875 | TimeOuts.to_fileopen = to; |
---|
2876 | else if (strcasecmp(name, "connect") == 0) |
---|
2877 | TimeOuts.to_connect = to; |
---|
2878 | else if (strcasecmp(name, "iconnect") == 0) |
---|
2879 | TimeOuts.to_iconnect = to; |
---|
2880 | else if (strcasecmp(name, "queuewarn") == 0) |
---|
2881 | { |
---|
2882 | to = convtime(val, 'h'); |
---|
2883 | if (p == NULL || strcmp(p, "*") == 0) |
---|
2884 | { |
---|
2885 | TimeOuts.to_q_warning[TOC_NORMAL] = to; |
---|
2886 | TimeOuts.to_q_warning[TOC_URGENT] = to; |
---|
2887 | TimeOuts.to_q_warning[TOC_NONURGENT] = to; |
---|
2888 | } |
---|
2889 | else if (strcasecmp(p, "normal") == 0) |
---|
2890 | TimeOuts.to_q_warning[TOC_NORMAL] = to; |
---|
2891 | else if (strcasecmp(p, "urgent") == 0) |
---|
2892 | TimeOuts.to_q_warning[TOC_URGENT] = to; |
---|
2893 | else if (strcasecmp(p, "non-urgent") == 0) |
---|
2894 | TimeOuts.to_q_warning[TOC_NONURGENT] = to; |
---|
2895 | else |
---|
2896 | syserr("settimeout: invalid queuewarn subtimeout %s", p); |
---|
2897 | } |
---|
2898 | else if (strcasecmp(name, "queuereturn") == 0) |
---|
2899 | { |
---|
2900 | to = convtime(val, 'd'); |
---|
2901 | if (p == NULL || strcmp(p, "*") == 0) |
---|
2902 | { |
---|
2903 | TimeOuts.to_q_return[TOC_NORMAL] = to; |
---|
2904 | TimeOuts.to_q_return[TOC_URGENT] = to; |
---|
2905 | TimeOuts.to_q_return[TOC_NONURGENT] = to; |
---|
2906 | } |
---|
2907 | else if (strcasecmp(p, "normal") == 0) |
---|
2908 | TimeOuts.to_q_return[TOC_NORMAL] = to; |
---|
2909 | else if (strcasecmp(p, "urgent") == 0) |
---|
2910 | TimeOuts.to_q_return[TOC_URGENT] = to; |
---|
2911 | else if (strcasecmp(p, "non-urgent") == 0) |
---|
2912 | TimeOuts.to_q_return[TOC_NONURGENT] = to; |
---|
2913 | else |
---|
2914 | syserr("settimeout: invalid queuereturn subtimeout %s", p); |
---|
2915 | } |
---|
2916 | else if (strcasecmp(name, "hoststatus") == 0) |
---|
2917 | MciInfoTimeout = convtime(val, 'm'); |
---|
2918 | else |
---|
2919 | syserr("settimeout: invalid timeout %s", name); |
---|
2920 | } |
---|