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