|
|
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.