|
|
1.1 root 1: # include <stdio.h>
2: # include <signal.h>
3: # include <ctype.h>
4: # include "dlvrmail.h"
5: # ifdef LOG
6: # include <log.h>
7: # endif LOG
8:
9: static char SccsId[] = "@(#)main.c 1.11 10/18/80";
10:
11: /*
12: ** DELIVERMAIL -- Deliver mail to a set of destinations
13: **
14: ** This is the basic mail router. All user mail programs should
15: ** call this routine to actually deliver mail. Delivermail in
16: ** turn calls a bunch of mail servers that do the real work of
17: ** delivering the mail.
18: **
19: ** Delivermail is driven by tables defined in config.c. This
20: ** file will be different from system to system, but the rest
21: ** of the code will be the same. This table could be read in,
22: ** but it seemed nicer to have it compiled in, since deliver-
23: ** mail will potentially be exercised a lot.
24: **
25: ** Usage:
26: ** /etc/delivermail [-f name] [-a] [-q] [-v] [-n] [-m] addr ...
27: **
28: ** Positional Parameters:
29: ** addr -- the address to deliver the mail to. There
30: ** can be several.
31: **
32: ** Flags:
33: ** -f name The mail is from "name" -- used for
34: ** the header in local mail, and to
35: ** deliver reports of failures to.
36: ** -r name Same as -f; however, this flag is
37: ** reserved to indicate special processing
38: ** for remote mail delivery as needed
39: ** in the future. So, network servers
40: ** should use -r.
41: ** -a This mail should be in ARPANET std
42: ** format (not used).
43: ** -n Don't do aliasing. This might be used
44: ** when delivering responses, for
45: ** instance.
46: ** -d Run in debug mode.
47: ** -em Mail back a response if there was an
48: ** error in processing. This should be
49: ** used when the origin of this message
50: ** is another machine.
51: ** -ew Write back a response if the user is
52: ** still logged in, otherwise, act like
53: ** -em.
54: ** -eq Don't print any error message (just
55: ** return exit status).
56: ** -ep (default) Print error messages
57: ** normally.
58: ** -ee Send BerkNet style errors. This
59: ** is equivalent to MailBack except
60: ** that it has gives zero return code
61: ** (unless there were errors during
62: ** returning). This used to be
63: ** "EchoBack", but you know how the old
64: ** software bounces.
65: ** -m In group expansion, send to the
66: ** sender also (stands for the Mail metoo
67: ** option.
68: ** -i Do not terminate mail on a line
69: ** containing just dot.
70: ** -s Save UNIX-like "From" lines on the
71: ** front of messages.
72: **
73: ** Return Codes:
74: ** As defined in <sysexits.h>.
75: **
76: ** These codes are actually returned from the auxiliary
77: ** mailers; it is their responsibility to make them
78: ** correct.
79: **
80: ** Compilation Flags:
81: ** LOG -- if set, everything is logged.
82: **
83: ** Compilation Instructions:
84: ** cc -c -O main.c config.c deliver.c parse.c
85: ** cc -n -s *.o -lS
86: ** chown root a.out
87: ** chmod 755 a.out
88: ** mv a.out delivermail
89: **
90: ** Deficiencies:
91: ** It ought to collect together messages that are
92: ** destined for a single host and send these
93: ** to the auxiliary mail server together.
94: ** It should take "user at host" as three separate
95: ** parameters and combine them into one address.
96: **
97: ** Author:
98: ** Eric Allman, UCB/INGRES
99: */
100:
101:
102:
103:
104:
105: bool ArpaFmt; /* mail is expected to be in ARPANET format */
106: bool FromFlag; /* from person is explicitly specified */
107: bool Debug; /* run in debug mode */
108: bool MailBack; /* mail back response on error */
109: bool BerkNet; /* called from BerkNet */
110: bool WriteBack; /* write back response on error */
111: bool HasXscrpt; /* if set, the transcript file exists */
112: bool NoAlias; /* don't do aliasing */
113: bool ForceMail; /* mail even if already sent a copy */
114: bool MeToo; /* send to the sender also if in a group expansion */
115: bool SaveFrom; /* save From lines on the front of messages */
116: bool IgnrDot; /* if set, ignore dot when collecting mail */
117: bool SuprErrs; /* supress errors if set */
118: int Errors; /* count of errors */
119: char InFileName[] = "/tmp/mailtXXXXXX";
120: char Transcript[] = "/tmp/mailxXXXXXX";
121: addrq From; /* the from person */
122: char *To; /* the target person */
123: int HopCount; /* hop count */
124: int ExitStat; /* the exit status byte */
125: addrq SendQ; /* queue of people to send to */
126: addrq AliasQ; /* queue of people who turned out to be aliases */
127:
128:
129:
130:
131:
132:
133: main(argc, argv)
134: int argc;
135: char **argv;
136: {
137: register char *p;
138: extern char *maketemp();
139: extern char *getname();
140: extern int finis();
141: extern addrq *parse();
142: register addrq *q;
143: extern char Version[];
144: extern int errno;
145: char *from;
146: register int i;
147: typedef int (*fnptr)();
148:
149: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
150: signal(SIGINT, finis);
151: signal(SIGTERM, finis);
152: setbuf(stdout, (char *) NULL);
153: # ifdef LOG
154: initlog("delivermail", 0, LOG_INDEP);
155: # endif LOG
156: # ifdef DEBUG
157: # ifdef DEBUGFILE
158: if ((i = open(DEBUGFILE, 1)) > 0)
159: {
160: lseek(i, 0L, 2);
161: close(1);
162: dup(i);
163: close(i);
164: Debug++;
165: }
166: # endif DEBUGFILE
167: # endif
168: errno = 0;
169: from = NULL;
170:
171: /*
172: ** Crack argv.
173: */
174:
175: while (--argc > 0 && (p = *++argv)[0] == '-')
176: {
177: switch (p[1])
178: {
179: case 'r': /* obsolete -f flag */
180: case 'f': /* from address */
181: p += 2;
182: if (*p == '\0')
183: {
184: p = *++argv;
185: if (--argc <= 0 || *p == '-')
186: {
187: syserr("No \"from\" person");
188: argc++;
189: argv--;
190: break;
191: }
192: }
193: if (from != NULL)
194: {
195: syserr("More than one \"from\" person");
196: break;
197: }
198: from = p;
199: break;
200:
201: case 'h': /* hop count */
202: p += 2;
203: if (*p == '\0')
204: {
205: p = *++argv;
206: if (--argc <= 0 || *p < '0' || *p > '9')
207: {
208: syserr("Bad hop count (%s)", p);
209: argc++;
210: argv--;
211: break;
212: }
213: }
214: HopCount = atoi(p);
215: break;
216:
217: case 'e': /* error message disposition */
218: switch (p[2])
219: {
220: case 'p': /* print errors normally */
221: break; /* (default) */
222:
223: case 'q': /* be silent about it */
224: freopen("/dev/null", "w", stdout);
225: break;
226:
227: case 'm': /* mail back */
228: MailBack++;
229: openxscrpt();
230: break;
231:
232: case 'e': /* do berknet error processing */
233: BerkNet++;
234: openxscrpt();
235: break;
236:
237: case 'w': /* write back (or mail) */
238: WriteBack++;
239: openxscrpt();
240: break;
241: }
242: break;
243:
244: # ifdef DEBUG
245: case 'd': /* debug */
246: Debug++;
247: printf("%s\n", Version);
248: break;
249: # endif DEBUG
250:
251: case 'n': /* don't alias */
252: NoAlias++;
253: break;
254:
255: case 'm': /* send to me too */
256: MeToo++;
257: break;
258:
259: case 'i': /* don't let dot stop me */
260: IgnrDot++;
261: break;
262:
263: case 'a': /* arpanet format */
264: ArpaFmt++;
265: break;
266:
267: case 's': /* save From lines in headers */
268: SaveFrom++;
269: break;
270:
271: default:
272: /* at Eric Schmidt's suggestion, this will not be an error....
273: syserr("Unknown flag %s", p);
274: ... seems that upward compatibility will be easier. */
275: break;
276: }
277: }
278:
279: if (from != NULL && ArpaFmt)
280: syserr("-f and -a are mutually exclusive");
281:
282: /*
283: ** Get a temp file.
284: */
285:
286: p = maketemp();
287: if (from == NULL)
288: from = p;
289: # ifdef DEBUG
290: if (Debug)
291: printf("Message-Id: <%s>\n", MsgId);
292: # endif DEBUG
293:
294: /*
295: ** Figure out who it's coming from.
296: ** Under certain circumstances allow the user to say who
297: ** s/he is (using -f or -r). These are:
298: ** 1. The user's uid is zero (root).
299: ** 2. The user's login name is "network" (mail from
300: ** a network server).
301: ** 3. The user's login name is "uucp" (mail from the
302: ** uucp network).
303: ** 4. The address the user is trying to claim has a
304: ** "!" character in it (since #3 doesn't do it for
305: ** us if we are dialing out).
306: ** A better check to replace #3 & #4 would be if the
307: ** effective uid is "UUCP" -- this would require me
308: ** to rewrite getpwent to "grab" uucp as it went by,
309: ** make getname more nasty, do another passwd file
310: ** scan, or compile the UID of "UUCP" into the code,
311: ** all of which are reprehensible.
312: **
313: ** Assuming all of these fail, we figure out something
314: ** ourselves.
315: */
316:
317: errno = 0;
318: p = getname();
319: if (p == NULL || p[0] == '\0')
320: {
321: syserr("Who are you? (uid=%d)", getuid());
322: finis();
323: }
324: errno = 0;
325: if (from != NULL)
326: {
327: if (strcmp(p, "network") != 0 && strcmp(p, "uucp") != 0 &&
328: index(from, '!') == NULL && getuid() != 0)
329: {
330: /* network sends -r regardless (why why why?) */
331: /* syserr("%s, you cannot use the -f flag", p); */
332: from = NULL;
333: }
334: }
335: if (from == NULL || from[0] == '\0')
336: from = p;
337: else
338: FromFlag++;
339: SuprErrs = TRUE;
340: if (parse(from, &From, 0) == NULL)
341: {
342: /* too many arpanet hosts generate garbage From addresses ....
343: syserr("Bad from address `%s'", from);
344: .... so we will just ignore this address */
345: from = p;
346: FromFlag = FALSE;
347: }
348: SuprErrs = FALSE;
349:
350: # ifdef DEBUG
351: if (Debug)
352: printf("From person = \"%s\"\n", From.q_paddr);
353: # endif DEBUG
354:
355: if (argc <= 0)
356: usrerr("Usage: /etc/delivermail [flags] addr...");
357:
358: /*
359: ** Process Hop count.
360: ** The Hop count tells us how many times this message has
361: ** been processed by delivermail. If it exceeds some
362: ** fairly large threshold, then we assume that we have
363: ** an infinite forwarding loop and die.
364: */
365:
366: if (++HopCount > MAXHOP)
367: syserr("Infinite forwarding loop (%s->%s)", From.q_paddr, *argv);
368:
369: /*
370: ** Scan argv and deliver the message to everyone.
371: */
372:
373: for (; argc-- > 0; argv++)
374: {
375: sendto(*argv, 0);
376: }
377:
378: /* if we have had errors sofar, drop out now */
379: if (Errors > 0 && ExitStat == EX_OK)
380: ExitStat = EX_USAGE;
381: if (ExitStat != EX_OK)
382: finis();
383:
384: /*
385: ** See if we have anyone to send to at all.
386: */
387:
388: if (nxtinq(&SendQ) == NULL && ExitStat == EX_OK)
389: {
390: syserr("Noone to send to!");
391: ExitStat = EX_USAGE;
392: finis();
393: }
394:
395: /*
396: ** Do aliasing.
397: ** First arrange that the person who is sending the mail
398: ** will not be expanded (unless explicitly requested).
399: */
400:
401: if (!MeToo)
402: recipient(&From, &AliasQ);
403: To = NULL;
404: alias();
405: if (nxtinq(&SendQ) == NULL && ExitStat == EX_OK)
406: {
407: /*
408: syserr("Vacant send queue; probably aliasing loop");
409: ExitStat = EX_SOFTWARE;
410: finis();
411: */
412: recipient(&From, &SendQ);
413: }
414:
415: /*
416: ** Actually send everything.
417: */
418:
419: for (q = &SendQ; (q = nxtinq(q)) != NULL; )
420: deliver(q, (fnptr) NULL);
421:
422: /*
423: ** All done.
424: */
425:
426: finis();
427: }
428: /*
429: ** FINIS -- Clean up and exit.
430: **
431: ** Parameters:
432: ** none
433: **
434: ** Returns:
435: ** never
436: **
437: ** Side Effects:
438: ** exits delivermail
439: **
440: ** Called By:
441: ** main
442: ** via signal on interrupt.
443: **
444: ** Deficiencies:
445: ** It may be that it should only remove the input
446: ** file if there have been no errors.
447: */
448:
449: finis()
450: {
451: /* mail back the transcript on errors */
452: if (ExitStat != EX_OK)
453: savemail();
454:
455: if (HasXscrpt)
456: unlink(Transcript);
457: unlink(InFileName);
458: exit(ExitStat);
459: }
460: /*
461: ** OPENXSCRPT -- Open transcript file
462: **
463: ** Creates a transcript file for possible eventual mailing or
464: ** sending back.
465: **
466: ** Parameters:
467: ** none
468: **
469: ** Returns:
470: ** none
471: **
472: ** Side Effects:
473: ** Turns the standard output into a special file
474: ** somewhere.
475: **
476: ** Called By:
477: ** main
478: */
479:
480: openxscrpt()
481: {
482: mktemp(Transcript);
483: HasXscrpt++;
484: if (freopen(Transcript, "w", stdout) == NULL)
485: syserr("Can't create %s", Transcript);
486: chmod(Transcript, 0600);
487: setbuf(stdout, (char *) NULL);
488: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.