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: #if !defined(lint) && !defined(NOSCCS) 12: static char SccsId[] = "@(#)savemail.c 5.7.1 (2.11BSD GTE) 3/7/95"; 13: #endif 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", sizeof buf - 20, 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: }