|
|
1.1 ! root 1: /* ! 2: ** Sendmail ! 3: ** Copyright (c) 1983 Eric P. Allman ! 4: ** Berkeley, California ! 5: ** ! 6: ** Copyright (c) 1983 Regents of the University of California. ! 7: ** All rights reserved. The Berkeley software License Agreement ! 8: ** specifies the terms and conditions for redistribution. ! 9: */ ! 10: ! 11: #ifndef lint ! 12: static char SccsId[] = "@(#)savemail.c 5.7 (Berkeley) 12/7/85"; ! 13: #endif not lint ! 14: ! 15: # include <pwd.h> ! 16: # include "sendmail.h" ! 17: ! 18: /* ! 19: ** SAVEMAIL -- Save mail on error ! 20: ** ! 21: ** If mailing back errors, mail it back to the originator ! 22: ** together with an error message; otherwise, just put it in ! 23: ** dead.letter in the user's home directory (if he exists on ! 24: ** this machine). ! 25: ** ! 26: ** Parameters: ! 27: ** e -- the envelope containing the message in error. ! 28: ** ! 29: ** Returns: ! 30: ** none ! 31: ** ! 32: ** Side Effects: ! 33: ** Saves the letter, by writing or mailing it back to the ! 34: ** sender, or by putting it in dead.letter in her home ! 35: ** directory. ! 36: */ ! 37: ! 38: /* defines for state machine */ ! 39: # define ESM_REPORT 0 /* report to sender's terminal */ ! 40: # define ESM_MAIL 1 /* mail back to sender */ ! 41: # define ESM_QUIET 2 /* messages have already been returned */ ! 42: # define ESM_DEADLETTER 3 /* save in ~/dead.letter */ ! 43: # define ESM_POSTMASTER 4 /* return to postmaster */ ! 44: # define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */ ! 45: # define ESM_PANIC 6 /* leave the locked queue/transcript files */ ! 46: # define ESM_DONE 7 /* the message is successfully delivered */ ! 47: ! 48: ! 49: savemail(e) ! 50: register ENVELOPE *e; ! 51: { ! 52: register struct passwd *pw; ! 53: register FILE *fp; ! 54: int state; ! 55: auto ADDRESS *q; ! 56: char buf[MAXLINE+1]; ! 57: extern struct passwd *getpwnam(); ! 58: register char *p; ! 59: extern char *ttypath(); ! 60: typedef int (*fnptr)(); ! 61: ! 62: # ifdef DEBUG ! 63: if (tTd(6, 1)) ! 64: printf("\nsavemail, ErrorMode = %c\n", ErrorMode); ! 65: # endif DEBUG ! 66: ! 67: if (bitset(EF_RESPONSE, e->e_flags)) ! 68: return; ! 69: if (e->e_class < 0) ! 70: { ! 71: message(Arpa_Info, "Dumping junk mail"); ! 72: return; ! 73: } ! 74: ForceMail = TRUE; ! 75: e->e_flags &= ~EF_FATALERRS; ! 76: ! 77: /* ! 78: ** In the unhappy event we don't know who to return the mail ! 79: ** to, make someone up. ! 80: */ ! 81: ! 82: if (e->e_from.q_paddr == NULL) ! 83: { ! 84: if (parseaddr("root", &e->e_from, 0, '\0') == NULL) ! 85: { ! 86: syserr("Cannot parse root!"); ! 87: ExitStat = EX_SOFTWARE; ! 88: finis(); ! 89: } ! 90: } ! 91: e->e_to = NULL; ! 92: ! 93: /* ! 94: ** Basic state machine. ! 95: ** ! 96: ** This machine runs through the following states: ! 97: ** ! 98: ** ESM_QUIET Errors have already been printed iff the ! 99: ** sender is local. ! 100: ** ESM_REPORT Report directly to the sender's terminal. ! 101: ** ESM_MAIL Mail response to the sender. ! 102: ** ESM_DEADLETTER Save response in ~/dead.letter. ! 103: ** ESM_POSTMASTER Mail response to the postmaster. ! 104: ** ESM_PANIC Save response anywhere possible. ! 105: */ ! 106: ! 107: /* determine starting state */ ! 108: switch (ErrorMode) ! 109: { ! 110: case EM_WRITE: ! 111: state = ESM_REPORT; ! 112: break; ! 113: ! 114: case EM_BERKNET: ! 115: /* mail back, but return o.k. exit status */ ! 116: ExitStat = EX_OK; ! 117: ! 118: /* fall through.... */ ! 119: ! 120: case EM_MAIL: ! 121: state = ESM_MAIL; ! 122: break; ! 123: ! 124: case EM_PRINT: ! 125: case '\0': ! 126: state = ESM_QUIET; ! 127: break; ! 128: ! 129: case EM_QUIET: ! 130: /* no need to return anything at all */ ! 131: return; ! 132: ! 133: default: ! 134: syserr("savemail: ErrorMode x%x\n"); ! 135: state = ESM_MAIL; ! 136: break; ! 137: } ! 138: ! 139: while (state != ESM_DONE) ! 140: { ! 141: # ifdef DEBUG ! 142: if (tTd(6, 5)) ! 143: printf(" state %d\n", state); ! 144: # endif DEBUG ! 145: ! 146: switch (state) ! 147: { ! 148: case ESM_QUIET: ! 149: if (e->e_from.q_mailer == LocalMailer) ! 150: state = ESM_DEADLETTER; ! 151: else ! 152: state = ESM_MAIL; ! 153: break; ! 154: ! 155: case ESM_REPORT: ! 156: ! 157: /* ! 158: ** If the user is still logged in on the same terminal, ! 159: ** then write the error messages back to hir (sic). ! 160: */ ! 161: ! 162: p = ttypath(); ! 163: if (p == NULL || freopen(p, "w", stdout) == NULL) ! 164: { ! 165: state = ESM_MAIL; ! 166: break; ! 167: } ! 168: ! 169: expand("\001n", buf, &buf[sizeof buf - 1], e); ! 170: printf("\r\nMessage from %s...\r\n", buf); ! 171: printf("Errors occurred while sending mail.\r\n"); ! 172: if (e->e_xfp != NULL) ! 173: { ! 174: (void) fflush(e->e_xfp); ! 175: fp = fopen(queuename(e, 'x'), "r"); ! 176: } ! 177: else ! 178: fp = NULL; ! 179: if (fp == NULL) ! 180: { ! 181: syserr("Cannot open %s", queuename(e, 'x')); ! 182: printf("Transcript of session is unavailable.\r\n"); ! 183: } ! 184: else ! 185: { ! 186: printf("Transcript follows:\r\n"); ! 187: while (fgets(buf, sizeof buf, fp) != NULL && ! 188: !ferror(stdout)) ! 189: fputs(buf, stdout); ! 190: (void) fclose(fp); ! 191: } ! 192: printf("Original message will be saved in dead.letter.\r\n"); ! 193: if (ferror(stdout)) ! 194: (void) syserr("savemail: stdout: write err"); ! 195: state = ESM_DEADLETTER; ! 196: break; ! 197: ! 198: case ESM_MAIL: ! 199: case ESM_POSTMASTER: ! 200: /* ! 201: ** If mailing back, do it. ! 202: ** Throw away all further output. Don't alias, ! 203: ** since this could cause loops, e.g., if joe ! 204: ** mails to joe@x, and for some reason the network ! 205: ** for @x is down, then the response gets sent to ! 206: ** joe@x, which gives a response, etc. Also force ! 207: ** the mail to be delivered even if a version of ! 208: ** it has already been sent to the sender. ! 209: */ ! 210: ! 211: if (state == ESM_MAIL) ! 212: { ! 213: if (e->e_errorqueue == NULL) ! 214: sendtolist(e->e_from.q_paddr, ! 215: (ADDRESS *) NULL, ! 216: &e->e_errorqueue); ! 217: ! 218: /* deliver a cc: to the postmaster if desired */ ! 219: if (PostMasterCopy != NULL) ! 220: sendtolist(PostMasterCopy, ! 221: (ADDRESS *) NULL, ! 222: &e->e_errorqueue); ! 223: q = e->e_errorqueue; ! 224: } ! 225: else ! 226: { ! 227: if (parseaddr("postmaster", q, 0, '\0') == NULL) ! 228: { ! 229: syserr("cannot parse postmaster!"); ! 230: ExitStat = EX_SOFTWARE; ! 231: state = ESM_USRTMP; ! 232: break; ! 233: } ! 234: } ! 235: if (returntosender(e->e_message != NULL ? e->e_message : ! 236: "Unable to deliver mail", ! 237: q, TRUE) == 0) ! 238: { ! 239: state = ESM_DONE; ! 240: break; ! 241: } ! 242: ! 243: state = state == ESM_MAIL ? ESM_POSTMASTER : ESM_USRTMP; ! 244: break; ! 245: ! 246: case ESM_DEADLETTER: ! 247: /* ! 248: ** Save the message in dead.letter. ! 249: ** If we weren't mailing back, and the user is ! 250: ** local, we should save the message in ! 251: ** ~/dead.letter so that the poor person doesn't ! 252: ** have to type it over again -- and we all know ! 253: ** what poor typists UNIX users are. ! 254: */ ! 255: ! 256: p = NULL; ! 257: if (e->e_from.q_mailer == LocalMailer) ! 258: { ! 259: if (e->e_from.q_home != NULL) ! 260: p = e->e_from.q_home; ! 261: else if ((pw = getpwnam(e->e_from.q_user)) != NULL) ! 262: p = pw->pw_dir; ! 263: } ! 264: if (p == NULL) ! 265: { ! 266: syserr("Can't return mail to %s", e->e_from.q_paddr); ! 267: state = ESM_MAIL; ! 268: break; ! 269: } ! 270: if (e->e_dfp != NULL) ! 271: { ! 272: auto ADDRESS *q; ! 273: bool oldverb = Verbose; ! 274: ! 275: /* we have a home directory; open dead.letter */ ! 276: define('z', p, e); ! 277: expand("\001z/dead.letter", buf, &buf[sizeof buf - 1], e); ! 278: Verbose = TRUE; ! 279: message(Arpa_Info, "Saving message in %s", buf); ! 280: Verbose = oldverb; ! 281: e->e_to = buf; ! 282: q = NULL; ! 283: sendtolist(buf, (ADDRESS *) NULL, &q); ! 284: if (deliver(e, q) == 0) ! 285: state = ESM_DONE; ! 286: else ! 287: state = ESM_MAIL; ! 288: } ! 289: else ! 290: { ! 291: /* no data file -- try mailing back */ ! 292: state = ESM_MAIL; ! 293: } ! 294: break; ! 295: ! 296: case ESM_USRTMP: ! 297: /* ! 298: ** Log the mail in /usr/tmp/dead.letter. ! 299: */ ! 300: ! 301: fp = dfopen("/usr/tmp/dead.letter", "a"); ! 302: if (fp == NULL) ! 303: { ! 304: state = ESM_PANIC; ! 305: break; ! 306: } ! 307: ! 308: putfromline(fp, ProgMailer); ! 309: (*e->e_puthdr)(fp, ProgMailer, e); ! 310: putline("\n", fp, ProgMailer); ! 311: (*e->e_putbody)(fp, ProgMailer, e); ! 312: putline("\n", fp, ProgMailer); ! 313: (void) fflush(fp); ! 314: state = ferror(fp) ? ESM_PANIC : ESM_DONE; ! 315: (void) fclose(fp); ! 316: break; ! 317: ! 318: default: ! 319: syserr("savemail: unknown state %d", state); ! 320: ! 321: /* fall through ... */ ! 322: ! 323: case ESM_PANIC: ! 324: syserr("savemail: HELP!!!!"); ! 325: # ifdef LOG ! 326: if (LogLevel >= 1) ! 327: syslog(LOG_ALERT, "savemail: HELP!!!!"); ! 328: # endif LOG ! 329: ! 330: /* leave the locked queue & transcript files around */ ! 331: exit(EX_SOFTWARE); ! 332: } ! 333: } ! 334: } ! 335: /* ! 336: ** RETURNTOSENDER -- return a message to the sender with an error. ! 337: ** ! 338: ** Parameters: ! 339: ** msg -- the explanatory message. ! 340: ** returnq -- the queue of people to send the message to. ! 341: ** sendbody -- if TRUE, also send back the body of the ! 342: ** message; otherwise just send the header. ! 343: ** ! 344: ** Returns: ! 345: ** zero -- if everything went ok. ! 346: ** else -- some error. ! 347: ** ! 348: ** Side Effects: ! 349: ** Returns the current message to the sender via ! 350: ** mail. ! 351: */ ! 352: ! 353: static bool SendBody; ! 354: ! 355: #define MAXRETURNS 6 /* max depth of returning messages */ ! 356: ! 357: returntosender(msg, returnq, sendbody) ! 358: char *msg; ! 359: ADDRESS *returnq; ! 360: bool sendbody; ! 361: { ! 362: char buf[MAXNAME]; ! 363: extern putheader(), errbody(); ! 364: register ENVELOPE *ee; ! 365: extern ENVELOPE *newenvelope(); ! 366: ENVELOPE errenvelope; ! 367: static int returndepth; ! 368: register ADDRESS *q; ! 369: ! 370: # ifdef DEBUG ! 371: if (tTd(6, 1)) ! 372: { ! 373: printf("Return To Sender: msg=\"%s\", depth=%d, CurEnv=%x,\n", ! 374: msg, returndepth, CurEnv); ! 375: printf("\treturnq="); ! 376: printaddr(returnq, TRUE); ! 377: } ! 378: # endif DEBUG ! 379: ! 380: if (++returndepth >= MAXRETURNS) ! 381: { ! 382: if (returndepth != MAXRETURNS) ! 383: syserr("returntosender: infinite recursion on %s", returnq->q_paddr); ! 384: /* don't "unrecurse" and fake a clean exit */ ! 385: /* returndepth--; */ ! 386: return (0); ! 387: } ! 388: ! 389: SendBody = sendbody; ! 390: define('g', "\001f", CurEnv); ! 391: ee = newenvelope(&errenvelope); ! 392: define('a', "\001b", ee); ! 393: ee->e_puthdr = putheader; ! 394: ee->e_putbody = errbody; ! 395: ee->e_flags |= EF_RESPONSE; ! 396: ee->e_sendqueue = returnq; ! 397: openxscript(ee); ! 398: for (q = returnq; q != NULL; q = q->q_next) ! 399: { ! 400: if (q->q_alias == NULL) ! 401: addheader("to", q->q_paddr, ee); ! 402: } ! 403: ! 404: (void) sprintf(buf, "Returned mail: %s", msg); ! 405: addheader("subject", buf, ee); ! 406: ! 407: /* fake up an address header for the from person */ ! 408: expand("\001n", buf, &buf[sizeof buf - 1], CurEnv); ! 409: if (parseaddr(buf, &ee->e_from, -1, '\0') == NULL) ! 410: { ! 411: syserr("Can't parse myself!"); ! 412: ExitStat = EX_SOFTWARE; ! 413: returndepth--; ! 414: return (-1); ! 415: } ! 416: loweraddr(&ee->e_from); ! 417: ! 418: /* push state into submessage */ ! 419: CurEnv = ee; ! 420: define('f', "\001n", ee); ! 421: define('x', "Mail Delivery Subsystem", ee); ! 422: eatheader(ee); ! 423: ! 424: /* actually deliver the error message */ ! 425: sendall(ee, SM_DEFAULT); ! 426: ! 427: /* restore state */ ! 428: dropenvelope(ee); ! 429: CurEnv = CurEnv->e_parent; ! 430: returndepth--; ! 431: ! 432: /* should check for delivery errors here */ ! 433: return (0); ! 434: } ! 435: /* ! 436: ** ERRBODY -- output the body of an error message. ! 437: ** ! 438: ** Typically this is a copy of the transcript plus a copy of the ! 439: ** original offending message. ! 440: ** ! 441: ** Parameters: ! 442: ** fp -- the output file. ! 443: ** m -- the mailer to output to. ! 444: ** e -- the envelope we are working in. ! 445: ** ! 446: ** Returns: ! 447: ** none ! 448: ** ! 449: ** Side Effects: ! 450: ** Outputs the body of an error message. ! 451: */ ! 452: ! 453: errbody(fp, m, e) ! 454: register FILE *fp; ! 455: register struct mailer *m; ! 456: register ENVELOPE *e; ! 457: { ! 458: register FILE *xfile; ! 459: char buf[MAXLINE]; ! 460: char *p; ! 461: ! 462: /* ! 463: ** Output transcript of errors ! 464: */ ! 465: ! 466: (void) fflush(stdout); ! 467: p = queuename(e->e_parent, 'x'); ! 468: if ((xfile = fopen(p, "r")) == NULL) ! 469: { ! 470: syserr("Cannot open %s", p); ! 471: fprintf(fp, " ----- Transcript of session is unavailable -----\n"); ! 472: } ! 473: else ! 474: { ! 475: fprintf(fp, " ----- Transcript of session follows -----\n"); ! 476: if (e->e_xfp != NULL) ! 477: (void) fflush(e->e_xfp); ! 478: while (fgets(buf, sizeof buf, xfile) != NULL) ! 479: putline(buf, fp, m); ! 480: (void) fclose(xfile); ! 481: } ! 482: errno = 0; ! 483: ! 484: /* ! 485: ** Output text of original message ! 486: */ ! 487: ! 488: if (NoReturn) ! 489: fprintf(fp, "\n ----- Return message suppressed -----\n\n"); ! 490: else if (e->e_parent->e_dfp != NULL) ! 491: { ! 492: if (SendBody) ! 493: { ! 494: putline("\n", fp, m); ! 495: putline(" ----- Unsent message follows -----\n", fp, m); ! 496: (void) fflush(fp); ! 497: putheader(fp, m, e->e_parent); ! 498: putline("\n", fp, m); ! 499: putbody(fp, m, e->e_parent); ! 500: } ! 501: else ! 502: { ! 503: putline("\n", fp, m); ! 504: putline(" ----- Message header follows -----\n", fp, m); ! 505: (void) fflush(fp); ! 506: putheader(fp, m, e->e_parent); ! 507: } ! 508: } ! 509: else ! 510: { ! 511: putline("\n", fp, m); ! 512: putline(" ----- No message was collected -----\n", fp, m); ! 513: putline("\n", fp, m); ! 514: } ! 515: ! 516: /* ! 517: ** Cleanup and exit ! 518: */ ! 519: ! 520: if (errno != 0) ! 521: syserr("errbody: I/O error"); ! 522: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.