|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 20729 (0x50f9) Types: TextFile Names: »savemail.c,v«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦bfebc70e2⟧ »EurOpenD3/mail/sendmail-5.65b+IDA-1.4.3.tar.Z« └─⟦f9e35cd84⟧ └─⟦this⟧ »sendmail/src/RCS/savemail.c,v«
head 5.13; branch 5.13.0; access; symbols UICSO:5.13.0 VANILLA:5.13; locks; strict; comment @ * @; 5.13 date 90.06.20.08.36.24; author paul; state Exp; branches 5.13.0.1; next ; 5.13.0.1 date 90.06.20.09.43.57; author paul; state Exp; branches; next 5.13.0.2; 5.13.0.2 date 90.06.20.13.58.01; author paul; state Exp; branches; next 5.13.0.3; 5.13.0.3 date 90.07.20.16.05.37; author paul; state Exp; branches; next 5.13.0.4; 5.13.0.4 date 90.08.27.16.49.46; author paul; state Exp; branches; next 5.13.0.5; 5.13.0.5 date 90.10.02.00.44.06; author paul; state Exp; branches; next 5.13.0.6; 5.13.0.6 date 90.10.13.19.10.23; author paul; state Exp; branches; next 5.13.0.7; 5.13.0.7 date 90.11.24.21.54.57; author paul; state Exp; branches; next 5.13.0.8; 5.13.0.8 date 91.01.19.19.26.02; author paul; state Exp; branches; next 5.13.0.9; 5.13.0.9 date 91.02.17.05.16.13; author paul; state Exp; branches; next 5.13.0.10; 5.13.0.10 date 91.03.04.21.48.23; author paul; state Exp; branches; next 5.13.0.11; 5.13.0.11 date 91.03.05.16.42.59; author paul; state Exp; branches; next 5.13.0.12; 5.13.0.12 date 91.03.06.15.13.33; author paul; state Exp; branches; next ; desc @@ 5.13 log @5.64 Berkeley release @ text @/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted provided * that: (1) source distributions retain this entire copyright notice and * comment, and (2) distributions including binaries display the following * acknowledgement: ``This product includes software developed by the * University of California, Berkeley and its contributors'' in the * documentation or other materials provided with the distribution and in * all advertising materials mentioning features or use of this software. * Neither the name of the University nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef lint static char sccsid[] = "@@(#)savemail.c 5.13 (Berkeley) 6/1/90"; #endif /* not lint */ # include <sys/types.h> # include <pwd.h> # include "sendmail.h" /* ** SAVEMAIL -- Save mail on error ** ** If mailing back errors, mail it back to the originator ** together with an error message; otherwise, just put it in ** dead.letter in the user's home directory (if he exists on ** this machine). ** ** Parameters: ** e -- the envelope containing the message in error. ** ** Returns: ** none ** ** Side Effects: ** Saves the letter, by writing or mailing it back to the ** sender, or by putting it in dead.letter in her home ** directory. */ /* defines for state machine */ # define ESM_REPORT 0 /* report to sender's terminal */ # define ESM_MAIL 1 /* mail back to sender */ # define ESM_QUIET 2 /* messages have already been returned */ # define ESM_DEADLETTER 3 /* save in ~/dead.letter */ # define ESM_POSTMASTER 4 /* return to postmaster */ # define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */ # define ESM_PANIC 6 /* leave the locked queue/transcript files */ # define ESM_DONE 7 /* the message is successfully delivered */ savemail(e) register ENVELOPE *e; { register struct passwd *pw; register FILE *fp; int state; auto ADDRESS *q; char buf[MAXLINE+1]; extern struct passwd *getpwnam(); register char *p; extern char *ttypath(); typedef int (*fnptr)(); if (tTd(6, 1)) printf("\nsavemail, ErrorMode = %c\n", ErrorMode); if (bitset(EF_RESPONSE, e->e_flags)) return; if (e->e_class < 0) { message(Arpa_Info, "Dumping junk mail"); return; } ForceMail = TRUE; e->e_flags &= ~EF_FATALERRS; /* ** In the unhappy event we don't know who to return the mail ** to, make someone up. */ if (e->e_from.q_paddr == NULL) { if (parseaddr("root", &e->e_from, 0, '\0') == NULL) { syserr("Cannot parse root!"); ExitStat = EX_SOFTWARE; finis(); } } e->e_to = NULL; /* ** Basic state machine. ** ** This machine runs through the following states: ** ** ESM_QUIET Errors have already been printed iff the ** sender is local. ** ESM_REPORT Report directly to the sender's terminal. ** ESM_MAIL Mail response to the sender. ** ESM_DEADLETTER Save response in ~/dead.letter. ** ESM_POSTMASTER Mail response to the postmaster. ** ESM_PANIC Save response anywhere possible. */ /* determine starting state */ switch (ErrorMode) { case EM_WRITE: state = ESM_REPORT; break; case EM_BERKNET: /* mail back, but return o.k. exit status */ ExitStat = EX_OK; /* fall through.... */ case EM_MAIL: state = ESM_MAIL; break; case EM_PRINT: case '\0': state = ESM_QUIET; break; case EM_QUIET: /* no need to return anything at all */ return; default: syserr("savemail: ErrorMode x%x\n"); state = ESM_MAIL; break; } while (state != ESM_DONE) { if (tTd(6, 5)) printf(" state %d\n", state); switch (state) { case ESM_QUIET: if (e->e_from.q_mailer == LocalMailer) state = ESM_DEADLETTER; else state = ESM_MAIL; break; case ESM_REPORT: /* ** If the user is still logged in on the same terminal, ** then write the error messages back to hir (sic). */ p = ttypath(); if (p == NULL || freopen(p, "w", stdout) == NULL) { state = ESM_MAIL; break; } expand("\001n", buf, &buf[sizeof buf - 1], e); printf("\r\nMessage from %s...\r\n", buf); printf("Errors occurred while sending mail.\r\n"); if (e->e_xfp != NULL) { (void) fflush(e->e_xfp); fp = fopen(queuename(e, 'x'), "r"); } else fp = NULL; if (fp == NULL) { syserr("Cannot open %s", queuename(e, 'x')); printf("Transcript of session is unavailable.\r\n"); } else { printf("Transcript follows:\r\n"); while (fgets(buf, sizeof buf, fp) != NULL && !ferror(stdout)) fputs(buf, stdout); (void) fclose(fp); } printf("Original message will be saved in dead.letter.\r\n"); state = ESM_DEADLETTER; break; case ESM_MAIL: case ESM_POSTMASTER: /* ** If mailing back, do it. ** Throw away all further output. Don't alias, ** since this could cause loops, e.g., if joe ** mails to joe@@x, and for some reason the network ** for @@x is down, then the response gets sent to ** joe@@x, which gives a response, etc. Also force ** the mail to be delivered even if a version of ** it has already been sent to the sender. */ if (state == ESM_MAIL) { if (e->e_errorqueue == NULL) sendtolist(e->e_from.q_paddr, (ADDRESS *) NULL, &e->e_errorqueue); /* deliver a cc: to the postmaster if desired */ if (PostMasterCopy != NULL) sendtolist(PostMasterCopy, (ADDRESS *) NULL, &e->e_errorqueue); q = e->e_errorqueue; } else { if (parseaddr("postmaster", q, 0, '\0') == NULL) { syserr("cannot parse postmaster!"); ExitStat = EX_SOFTWARE; state = ESM_USRTMP; break; } } if (returntosender(e->e_message != NULL ? e->e_message : "Unable to deliver mail", q, TRUE) == 0) { state = ESM_DONE; break; } state = state == ESM_MAIL ? ESM_POSTMASTER : ESM_USRTMP; break; case ESM_DEADLETTER: /* ** Save the message in dead.letter. ** If we weren't mailing back, and the user is ** local, we should save the message in ** ~/dead.letter so that the poor person doesn't ** have to type it over again -- and we all know ** what poor typists UNIX users are. */ p = NULL; if (e->e_from.q_mailer == LocalMailer) { if (e->e_from.q_home != NULL) p = e->e_from.q_home; else if ((pw = getpwnam(e->e_from.q_user)) != NULL) p = pw->pw_dir; } if (p == NULL) { syserr("Can't return mail to %s", e->e_from.q_paddr); state = ESM_MAIL; break; } if (e->e_dfp != NULL) { auto ADDRESS *q; bool oldverb = Verbose; /* we have a home directory; open dead.letter */ define('z', p, e); expand("\001z/dead.letter", buf, &buf[sizeof buf - 1], e); Verbose = TRUE; message(Arpa_Info, "Saving message in %s", buf); Verbose = oldverb; e->e_to = buf; q = NULL; sendtolist(buf, (ADDRESS *) NULL, &q); if (deliver(e, q) == 0) state = ESM_DONE; else state = ESM_MAIL; } else { /* no data file -- try mailing back */ state = ESM_MAIL; } break; case ESM_USRTMP: /* ** Log the mail in /usr/tmp/dead.letter. */ fp = dfopen("/usr/tmp/dead.letter", "a"); if (fp == NULL) { state = ESM_PANIC; break; } putfromline(fp, ProgMailer); (*e->e_puthdr)(fp, ProgMailer, e); putline("\n", fp, ProgMailer); (*e->e_putbody)(fp, ProgMailer, e); putline("\n", fp, ProgMailer); (void) fflush(fp); state = ferror(fp) ? ESM_PANIC : ESM_DONE; (void) fclose(fp); break; default: syserr("savemail: unknown state %d", state); /* fall through ... */ case ESM_PANIC: syserr("savemail: HELP!!!!"); # ifdef LOG if (LogLevel >= 1) syslog(LOG_ALERT, "savemail: HELP!!!!"); # endif LOG /* leave the locked queue & transcript files around */ exit(EX_SOFTWARE); } } } \f /* ** RETURNTOSENDER -- return a message to the sender with an error. ** ** Parameters: ** msg -- the explanatory message. ** returnq -- the queue of people to send the message to. ** sendbody -- if TRUE, also send back the body of the ** message; otherwise just send the header. ** ** Returns: ** zero -- if everything went ok. ** else -- some error. ** ** Side Effects: ** Returns the current message to the sender via ** mail. */ static bool SendBody; #define MAXRETURNS 6 /* max depth of returning messages */ returntosender(msg, returnq, sendbody) char *msg; ADDRESS *returnq; bool sendbody; { char buf[MAXNAME]; extern putheader(), errbody(); register ENVELOPE *ee; extern ENVELOPE *newenvelope(); ENVELOPE errenvelope; static int returndepth; register ADDRESS *q; if (tTd(6, 1)) { printf("Return To Sender: msg=\"%s\", depth=%d, CurEnv=%x,\n", msg, returndepth, CurEnv); printf("\treturnq="); printaddr(returnq, TRUE); } if (++returndepth >= MAXRETURNS) { if (returndepth != MAXRETURNS) syserr("returntosender: infinite recursion on %s", returnq->q_paddr); /* don't "unrecurse" and fake a clean exit */ /* returndepth--; */ return (0); } SendBody = sendbody; define('g', "\001f", CurEnv); ee = newenvelope(&errenvelope); define('a', "\001b", ee); ee->e_puthdr = putheader; ee->e_putbody = errbody; ee->e_flags |= EF_RESPONSE; ee->e_sendqueue = returnq; openxscript(ee); for (q = returnq; q != NULL; q = q->q_next) { if (q->q_alias == NULL) addheader("to", q->q_paddr, ee); } (void) sprintf(buf, "Returned mail: %s", msg); addheader("subject", buf, ee); /* fake up an address header for the from person */ expand("\001n", buf, &buf[sizeof buf - 1], CurEnv); if (parseaddr(buf, &ee->e_from, -1, '\0') == NULL) { syserr("Can't parse myself!"); ExitStat = EX_SOFTWARE; returndepth--; return (-1); } loweraddr(&ee->e_from); /* push state into submessage */ CurEnv = ee; define('f', "\001n", ee); define('x', "Mail Delivery Subsystem", ee); eatheader(ee); /* actually deliver the error message */ sendall(ee, SM_DEFAULT); /* restore state */ dropenvelope(ee); CurEnv = CurEnv->e_parent; returndepth--; /* should check for delivery errors here */ return (0); } \f /* ** ERRBODY -- output the body of an error message. ** ** Typically this is a copy of the transcript plus a copy of the ** original offending message. ** ** Parameters: ** fp -- the output file. ** m -- the mailer to output to. ** e -- the envelope we are working in. ** ** Returns: ** none ** ** Side Effects: ** Outputs the body of an error message. */ errbody(fp, m, e) register FILE *fp; register struct mailer *m; register ENVELOPE *e; { register FILE *xfile; char buf[MAXLINE]; char *p; /* ** Output transcript of errors */ (void) fflush(stdout); p = queuename(e->e_parent, 'x'); if ((xfile = fopen(p, "r")) == NULL) { syserr("Cannot open %s", p); fprintf(fp, " ----- Transcript of session is unavailable -----\n"); } else { fprintf(fp, " ----- Transcript of session follows -----\n"); if (e->e_xfp != NULL) (void) fflush(e->e_xfp); while (fgets(buf, sizeof buf, xfile) != NULL) putline(buf, fp, m); (void) fclose(xfile); } errno = 0; /* ** Output text of original message */ if (NoReturn) fprintf(fp, "\n ----- Return message suppressed -----\n\n"); else if (e->e_parent->e_dfp != NULL) { if (SendBody) { putline("\n", fp, m); putline(" ----- Unsent message follows -----\n", fp, m); (void) fflush(fp); putheader(fp, m, e->e_parent); putline("\n", fp, m); putbody(fp, m, e->e_parent); } else { putline("\n", fp, m); putline(" ----- Message header follows -----\n", fp, m); (void) fflush(fp); putheader(fp, m, e->e_parent); } } else { putline("\n", fp, m); putline(" ----- No message was collected -----\n", fp, m); putline("\n", fp, m); } /* ** Cleanup and exit */ if (errno != 0) syserr("errbody: I/O error"); } @ 5.13.0.1 log @IDA patches @ text @d222 6 d232 1 a232 1 if (PostMasterCopy != NULL) a233 32 if ((q = parseaddr(PostMasterCopy, NULL, 0, '\0')) == NULL) { if (!strcasecmp("postmaster", PostMasterCopy)) { syserr("cannot parse postmaster!"); ExitStat = EX_SOFTWARE; state = ESM_USRTMP; break; } else { syserr("cannot parse postmaster from OP!"); /* fake a new OP and try again */ free((char *) PostMasterCopy); PostMasterCopy = newstr("postmaster"); /* bad OP but return o.k. exit stat */ ExitStat = EX_OK; state = ESM_POSTMASTER; /* is this really necessary? */ q = e->e_errorqueue; break; } } alias(q, &q); } else if (parseaddr("postmaster", q, 0, '\0') == NULL) { d242 1 a242 2 q, state == ESM_MAIL) == 0 && state == ESM_POSTMASTER) d373 1 a373 3 ADDRESS *p, *q; char *to, *cc; int len; a395 3 /* undefine sending host & proto for error msg */ define('s', MACNULL, ee); define('r', MACNULL, ee); d401 2 a402 5 /* put the recipients in the to: header (cc: for PostMasterCopy) */ cc = NULL; to = buf; for (q = returnq; q != NULL; q = q->q_next) { d404 1 a404 24 if (PostMasterCopy && (strcmp(q->q_paddr, PostMasterCopy) == 0)) cc = q->q_paddr; else { /* Not Postmaster; already on the To: line? */ for (p = returnq; p != q; p = p->q_next) if (strcasecmp(p->q_paddr, q->q_paddr) == 0) break; if (p == q) { /* No, add it */ *to++ = ','; *to++ = ' '; len = strlen(q->q_paddr); if (q->q_paddr[0] == '<' && q->q_paddr[len-1] == '>' && q->q_paddr[1] != '@@') { /* Remove angle brackets; they aren't needed */ strncpy(to, q->q_paddr+1, len-2); to += len-2; } else { strcpy(to, q->q_paddr, len); to += len; } } } a405 5 *to = '\0'; if (to != buf) addheader("to", buf+2, ee); if (cc) addheader("cc", cc, ee); @ 5.13.0.2 log @Backed out header-only postmastercc patch as it was dying with unknown mailer error 1. @ text @a221 6 /* deliver a cc: to the postmaster if desired */ if (PostMasterCopy != NULL) sendtolist(PostMasterCopy, (ADDRESS *) NULL, &e->e_errorqueue); d226 1 a226 1 if (parseaddr("postmaster", q, 0, '\0') == NULL) d228 32 d268 2 a269 1 q, TRUE) == 0) d460 1 a460 1 } @ 5.13.0.3 log @Check for room in to string before adding chars to it (from Paul Vixie). @ text @a420 5 len = strlen(q->q_paddr); if (to+2+len+1 >= buf + sizeof buf) break; d424 1 @ 5.13.0.4 log @Return-Path: comp.mail.sendmail From: e07@@nikhefh.nikhef.nl (Eric Wassenaar) Date: 27 Aug 90 09:21:40 GMT Newsgroups: comp.mail.sendmail,comp.bugs.4bsd Subject: incorrect address rewriting during returntosender Ref: All versions of sendmail up to/including 5.64 Description: Sendmail will rewrite 'new style' addresses in the header lines incorrectly when returning a message to the sender, e.g. when mailing back a return receipt or an error message. Repeat-by: Send a message To: him@@hisdomain and ask for a Return-Receipt-To: Your Name <you@@yourdomain> Most probably (assuming his sendmail generates fully qualified addresses, and can handle 'old style' addresses) this appears in the return message as To: Your@@hisdomain, Name@@hisdomain, <you@@yourdomain> Analysis: Sendmail returns a message using the sequence sendtolist(recipient_list, ...) returntosender(...) The recipient(s) are parsed within sendtolist(), the 'new style' address is recognized, and the EF_OLDSTYLE bit is cleared in the envelope e_flags field. The actual delivery is done within returntosender(), but this routine switches to a temporary envelope which gets the default e_flags with the EF_OLDSTYLE bit set. During subsequent header rewriting, in putheader() and commaize(), the headers are handled incorrectly, with the above result. @ text @a402 2 if (!bitset(EF_OLDSTYLE, CurEnv->e_flags)) ee->e_flags &= ~EF_OLDSTYLE; @ 5.13.0.5 log @Changes from Berkeley's 5.64 to 5.65 release (main.c, savemail.c, and version.c) @ text @d22 1 a22 1 static char sccsid[] = "@@(#)savemail.c 5.14 (Berkeley) 8/29/90"; a402 1 ee->e_flags |= EF_RESPONSE; d405 1 @ 5.13.0.6 log @Bruce Lilly (bruce%balilly@@sonyd1.broadcast.sony.com) provided patch to strip extraneous newlines from putline() arguments. Fixed fencepost bug with third expand() argument. @ text @d66 1 a66 1 auto ADDRESS *q = NULL; d176 1 a176 1 expand("\001n", buf, &buf[(sizeof(buf)-1)], e); d194 1 a194 1 while (fgets(buf, sizeof(buf), fp) != NULL && d282 1 a282 1 expand("\001z/dead.letter", buf, &buf[(sizeof(buf)-1)], e); d315 1 a315 1 putline("", fp, ProgMailer); d317 1 a317 1 putline("", fp, ProgMailer); d425 1 a425 1 if (to+2+len+1 > buf + sizeof buf - 1) d453 1 a453 1 expand("\001n", buf, &buf[(sizeof(buf) - 1)], CurEnv); d539 2 a540 2 putline("", fp, m); putline(" ----- Unsent message follows -----", fp, m); d543 1 a543 1 putline("", fp, m); d548 2 a549 2 putline("", fp, m); putline(" ----- Message header follows -----", fp, m); d556 3 a558 3 putline("", fp, m); putline(" ----- No message was collected -----", fp, m); putline("", fp, m); @ 5.13.0.7 log @Change calls to putline() and parseaddr() to not use constant strings. Commented out tokens following #endif statements. @ text @d25 3 a27 3 #include <sys/types.h> #include <pwd.h> #include "sendmail.h" a58 2 static char Root[] = "root"; /* for gcc */ static char PostMaster[] = "postmaster"; d93 1 a93 1 if (parseaddr(Root, &e->e_from, 0, '\0') == NULL) d232 1 a232 1 if (parseaddr(PostMaster, q, 0, '\0') == NULL) d330 1 a330 1 #ifdef LOG d333 1 a333 1 #endif /* LOG */ d437 1 a437 1 (void) strcpy(to, q->q_paddr, len); d540 1 a540 2 (void) strcpy(buf, " ----- Unsent message follows -----"); putline(buf, fp, m); d549 1 a549 2 (void) strcpy(buf, " ----- Message header follows -----"); putline(buf, fp, m); d557 1 a557 2 (void) strcpy(buf, " ----- No message was collected -----"); putline(buf, fp, m); @ 5.13.0.8 log @Deleted #include <sys/types.h> as it's already included via sendmail.h from useful.h. #include "sendmail.h" relocated to top of #include list. @ text @d25 2 a27 1 #include <pwd.h> @ 5.13.0.9 log @Added static keyword to declaration of errbody(). @ text @d369 1 a369 2 extern putheader(); static errbody(); a498 1 static @ 5.13.0.10 log @ANSIfied. @ text @a27 6 #ifdef __STDC__ static void errbody(FILE *, MAILER *, ENVELOPE *); #else /* !__STDC__ */ static void errbody(); #endif /* __STDC__ */ a60 1 void d69 1 d71 1 d364 1 a364 1 const char *msg; d369 2 d372 1 d500 1 a500 1 static void d503 1 a503 1 register MAILER *m; @ 5.13.0.11 log @Put overly long headers (> 500 bytes) at end of message body. Adapted from Paul Vixie's patch. @ text @d471 1 a471 1 eatheader(ee, NULL); @ 5.13.0.12 log @strcpy() was used where strncpy was needed. @ text @d441 1 a441 1 (void) strncpy(to, q->q_paddr, len); @