envelope.c revision 38032
138032Speter/* 238032Speter * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 338032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 438032Speter * Copyright (c) 1988, 1993 538032Speter * The Regents of the University of California. All rights reserved. 638032Speter * 738032Speter * By using this file, you agree to the terms and conditions set 838032Speter * forth in the LICENSE file which can be found at the top level of 938032Speter * the sendmail distribution. 1038032Speter * 1138032Speter */ 1238032Speter 1338032Speter#ifndef lint 1438032Speterstatic char sccsid[] = "@(#)envelope.c 8.117 (Berkeley) 6/4/98"; 1538032Speter#endif /* not lint */ 1638032Speter 1738032Speter#include "sendmail.h" 1838032Speter 1938032Speter/* 2038032Speter** NEWENVELOPE -- allocate a new envelope 2138032Speter** 2238032Speter** Supports inheritance. 2338032Speter** 2438032Speter** Parameters: 2538032Speter** e -- the new envelope to fill in. 2638032Speter** parent -- the envelope to be the parent of e. 2738032Speter** 2838032Speter** Returns: 2938032Speter** e. 3038032Speter** 3138032Speter** Side Effects: 3238032Speter** none. 3338032Speter*/ 3438032Speter 3538032SpeterENVELOPE * 3638032Speternewenvelope(e, parent) 3738032Speter register ENVELOPE *e; 3838032Speter register ENVELOPE *parent; 3938032Speter{ 4038032Speter if (e == parent && e->e_parent != NULL) 4138032Speter parent = e->e_parent; 4238032Speter clearenvelope(e, TRUE); 4338032Speter if (e == CurEnv) 4438032Speter bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from); 4538032Speter else 4638032Speter bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from); 4738032Speter e->e_parent = parent; 4838032Speter e->e_ctime = curtime(); 4938032Speter if (parent != NULL) 5038032Speter e->e_msgpriority = parent->e_msgsize; 5138032Speter e->e_puthdr = putheader; 5238032Speter e->e_putbody = putbody; 5338032Speter if (CurEnv->e_xfp != NULL) 5438032Speter (void) fflush(CurEnv->e_xfp); 5538032Speter 5638032Speter return (e); 5738032Speter} 5838032Speter/* 5938032Speter** DROPENVELOPE -- deallocate an envelope. 6038032Speter** 6138032Speter** Parameters: 6238032Speter** e -- the envelope to deallocate. 6338032Speter** fulldrop -- if set, do return receipts. 6438032Speter** 6538032Speter** Returns: 6638032Speter** none. 6738032Speter** 6838032Speter** Side Effects: 6938032Speter** housekeeping necessary to dispose of an envelope. 7038032Speter** Unlocks this queue file. 7138032Speter*/ 7238032Speter 7338032Spetervoid 7438032Speterdropenvelope(e, fulldrop) 7538032Speter register ENVELOPE *e; 7638032Speter bool fulldrop; 7738032Speter{ 7838032Speter bool queueit = FALSE; 7938032Speter bool message_timeout = FALSE; 8038032Speter bool failure_return = FALSE; 8138032Speter bool delay_return = FALSE; 8238032Speter bool success_return = FALSE; 8338032Speter register ADDRESS *q; 8438032Speter char *id = e->e_id; 8538032Speter char buf[MAXLINE]; 8638032Speter 8738032Speter if (tTd(50, 1)) 8838032Speter { 8938032Speter extern void printenvflags __P((ENVELOPE *)); 9038032Speter 9138032Speter printf("dropenvelope %lx: id=", (u_long) e); 9238032Speter xputs(e->e_id); 9338032Speter printf(", flags="); 9438032Speter printenvflags(e); 9538032Speter if (tTd(50, 10)) 9638032Speter { 9738032Speter printf("sendq="); 9838032Speter printaddr(e->e_sendqueue, TRUE); 9938032Speter } 10038032Speter } 10138032Speter 10238032Speter if (LogLevel > 84) 10338032Speter sm_syslog(LOG_DEBUG, id, 10438032Speter "dropenvelope, e_flags=0x%x, OpMode=%c, pid=%d", 10538032Speter e->e_flags, OpMode, getpid()); 10638032Speter 10738032Speter /* we must have an id to remove disk files */ 10838032Speter if (id == NULL) 10938032Speter return; 11038032Speter 11138032Speter /* if verify-only mode, we can skip most of this */ 11238032Speter if (OpMode == MD_VERIFY) 11338032Speter goto simpledrop; 11438032Speter 11538032Speter if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) 11638032Speter logsender(e, NULL); 11738032Speter e->e_flags &= ~EF_LOGSENDER; 11838032Speter 11938032Speter /* post statistics */ 12038032Speter poststats(StatFile); 12138032Speter 12238032Speter /* 12338032Speter ** Extract state information from dregs of send list. 12438032Speter */ 12538032Speter 12638032Speter if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass]) 12738032Speter message_timeout = TRUE; 12838032Speter 12938032Speter e->e_flags &= ~EF_QUEUERUN; 13038032Speter for (q = e->e_sendqueue; q != NULL; q = q->q_next) 13138032Speter { 13238032Speter if (bitset(QQUEUEUP, q->q_flags) && 13338032Speter bitset(QDONTSEND, q->q_flags)) 13438032Speter { 13538032Speter /* I'm not sure how this happens..... */ 13638032Speter if (tTd(50, 2)) 13738032Speter { 13838032Speter printf("Bogus flags: "); 13938032Speter printaddr(q, FALSE); 14038032Speter } 14138032Speter q->q_flags &= ~QDONTSEND; 14238032Speter } 14338032Speter if (!bitset(QBADADDR|QDONTSEND|QSENT, q->q_flags)) 14438032Speter queueit = TRUE; 14538032Speter#if XDEBUG 14638032Speter else if (bitset(QQUEUEUP, q->q_flags)) 14738032Speter sm_syslog(LOG_DEBUG, e->e_id, 14838032Speter "dropenvelope: q_flags = %x, paddr = %s", 14938032Speter q->q_flags, q->q_paddr); 15038032Speter#endif 15138032Speter 15238032Speter /* see if a notification is needed */ 15338032Speter if (bitset(QPINGONFAILURE, q->q_flags) && 15438032Speter ((message_timeout && bitset(QQUEUEUP, q->q_flags)) || 15538032Speter bitset(QBADADDR, q->q_flags))) 15638032Speter { 15738032Speter failure_return = TRUE; 15838032Speter if (q->q_owner == NULL && !emptyaddr(&e->e_from)) 15938032Speter (void) sendtolist(e->e_from.q_paddr, NULLADDR, 16038032Speter &e->e_errorqueue, 0, e); 16138032Speter } 16238032Speter else if (bitset(QPINGONSUCCESS, q->q_flags) && 16338032Speter ((bitset(QSENT, q->q_flags) && 16438032Speter bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) || 16538032Speter bitset(QRELAYED|QEXPANDED|QDELIVERED, q->q_flags))) 16638032Speter { 16738032Speter success_return = TRUE; 16838032Speter } 16938032Speter } 17038032Speter 17138032Speter if (e->e_class < 0) 17238032Speter e->e_flags |= EF_NO_BODY_RETN; 17338032Speter 17438032Speter /* 17538032Speter ** See if the message timed out. 17638032Speter */ 17738032Speter 17838032Speter if (!queueit) 17938032Speter /* nothing to do */ ; 18038032Speter else if (message_timeout) 18138032Speter { 18238032Speter if (failure_return) 18338032Speter { 18438032Speter (void) snprintf(buf, sizeof buf, 18538032Speter "Cannot send message within %s", 18638032Speter pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); 18738032Speter if (e->e_message != NULL) 18838032Speter free(e->e_message); 18938032Speter e->e_message = newstr(buf); 19038032Speter message(buf); 19138032Speter e->e_flags |= EF_CLRQUEUE; 19238032Speter } 19338032Speter fprintf(e->e_xfp, "Message could not be delivered for %s\n", 19438032Speter pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); 19538032Speter fprintf(e->e_xfp, "Message will be deleted from queue\n"); 19638032Speter for (q = e->e_sendqueue; q != NULL; q = q->q_next) 19738032Speter { 19838032Speter if (!bitset(QBADADDR|QDONTSEND|QSENT, q->q_flags)) 19938032Speter { 20038032Speter q->q_flags |= QBADADDR; 20138032Speter q->q_status = "4.4.7"; 20238032Speter } 20338032Speter } 20438032Speter } 20538032Speter else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 && 20638032Speter curtime() > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass]) 20738032Speter { 20838032Speter if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) && 20938032Speter e->e_class >= 0 && 21038032Speter e->e_from.q_paddr != NULL && 21138032Speter strcmp(e->e_from.q_paddr, "<>") != 0 && 21238032Speter strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 && 21338032Speter (strlen(e->e_from.q_paddr) <= (SIZE_T) 8 || 21438032Speter strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0)) 21538032Speter { 21638032Speter for (q = e->e_sendqueue; q != NULL; q = q->q_next) 21738032Speter { 21838032Speter if (bitset(QQUEUEUP, q->q_flags) && 21938032Speter bitset(QPINGONDELAY, q->q_flags)) 22038032Speter { 22138032Speter q->q_flags |= QDELAYED; 22238032Speter delay_return = TRUE; 22338032Speter } 22438032Speter } 22538032Speter } 22638032Speter if (delay_return) 22738032Speter { 22838032Speter (void) snprintf(buf, sizeof buf, 22938032Speter "Warning: could not send message for past %s", 23038032Speter pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE)); 23138032Speter if (e->e_message != NULL) 23238032Speter free(e->e_message); 23338032Speter e->e_message = newstr(buf); 23438032Speter message(buf); 23538032Speter e->e_flags |= EF_WARNING; 23638032Speter } 23738032Speter fprintf(e->e_xfp, 23838032Speter "Warning: message still undelivered after %s\n", 23938032Speter pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE)); 24038032Speter fprintf(e->e_xfp, "Will keep trying until message is %s old\n", 24138032Speter pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); 24238032Speter } 24338032Speter 24438032Speter if (tTd(50, 2)) 24538032Speter printf("failure_return=%d delay_return=%d success_return=%d queueit=%d\n", 24638032Speter failure_return, delay_return, success_return, queueit); 24738032Speter 24838032Speter /* 24938032Speter ** If we had some fatal error, but no addresses are marked as 25038032Speter ** bad, mark them _all_ as bad. 25138032Speter */ 25238032Speter 25338032Speter if (bitset(EF_FATALERRS, e->e_flags) && !failure_return) 25438032Speter { 25538032Speter for (q = e->e_sendqueue; q != NULL; q = q->q_next) 25638032Speter { 25738032Speter if (!bitset(QDONTSEND, q->q_flags) && 25838032Speter bitset(QPINGONFAILURE, q->q_flags)) 25938032Speter { 26038032Speter failure_return = TRUE; 26138032Speter q->q_flags |= QBADADDR; 26238032Speter } 26338032Speter } 26438032Speter } 26538032Speter 26638032Speter /* 26738032Speter ** Send back return receipts as requested. 26838032Speter */ 26938032Speter 27038032Speter if (success_return && !failure_return && !delay_return && fulldrop && 27138032Speter !bitset(PRIV_NORECEIPTS, PrivacyFlags) && 27238032Speter strcmp(e->e_from.q_paddr, "<>") != 0) 27338032Speter { 27438032Speter auto ADDRESS *rlist = NULL; 27538032Speter 27638032Speter if (tTd(50, 8)) 27738032Speter printf("dropenvelope(%s): sending return receipt\n", id); 27838032Speter e->e_flags |= EF_SENDRECEIPT; 27938032Speter (void) sendtolist(e->e_from.q_paddr, NULLADDR, &rlist, 0, e); 28038032Speter (void) returntosender("Return receipt", rlist, RTSF_NO_BODY, e); 28138032Speter } 28238032Speter e->e_flags &= ~EF_SENDRECEIPT; 28338032Speter 28438032Speter /* 28538032Speter ** Arrange to send error messages if there are fatal errors. 28638032Speter */ 28738032Speter 28838032Speter if ((failure_return || delay_return) && e->e_errormode != EM_QUIET) 28938032Speter { 29038032Speter extern void savemail __P((ENVELOPE *, bool)); 29138032Speter 29238032Speter if (tTd(50, 8)) 29338032Speter printf("dropenvelope(%s): saving mail\n", id); 29438032Speter savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags)); 29538032Speter } 29638032Speter 29738032Speter /* 29838032Speter ** Arrange to send warning messages to postmaster as requested. 29938032Speter */ 30038032Speter 30138032Speter if ((failure_return || bitset(EF_PM_NOTIFY, e->e_flags)) && 30238032Speter PostMasterCopy != NULL && 30338032Speter !bitset(EF_RESPONSE, e->e_flags) && e->e_class >= 0) 30438032Speter { 30538032Speter auto ADDRESS *rlist = NULL; 30638032Speter 30738032Speter if (tTd(50, 8)) 30838032Speter printf("dropenvelope(%s): sending postmaster copy\n", id); 30938032Speter (void) sendtolist(PostMasterCopy, NULLADDR, &rlist, 0, e); 31038032Speter (void) returntosender(e->e_message, rlist, RTSF_PM_BOUNCE, e); 31138032Speter } 31238032Speter 31338032Speter /* 31438032Speter ** Instantiate or deinstantiate the queue. 31538032Speter */ 31638032Speter 31738032Spetersimpledrop: 31838032Speter if (tTd(50, 8)) 31938032Speter printf("dropenvelope(%s): at simpledrop, queueit=%d\n", 32038032Speter id, queueit); 32138032Speter if (!queueit || bitset(EF_CLRQUEUE, e->e_flags)) 32238032Speter { 32338032Speter if (tTd(50, 1)) 32438032Speter { 32538032Speter extern void printenvflags __P((ENVELOPE *)); 32638032Speter 32738032Speter printf("\n===== Dropping [dq]f%s... queueit=%d, e_flags=", 32838032Speter e->e_id, queueit); 32938032Speter printenvflags(e); 33038032Speter } 33138032Speter xunlink(queuename(e, 'd')); 33238032Speter xunlink(queuename(e, 'q')); 33338032Speter 33438032Speter if (LogLevel > 10) 33538032Speter sm_syslog(LOG_INFO, id, "done"); 33638032Speter } 33738032Speter else if (queueit || !bitset(EF_INQUEUE, e->e_flags)) 33838032Speter { 33938032Speter#if QUEUE 34038032Speter queueup(e, FALSE); 34138032Speter#else /* QUEUE */ 34238032Speter syserr("554 dropenvelope: queueup"); 34338032Speter#endif /* QUEUE */ 34438032Speter } 34538032Speter 34638032Speter /* now unlock the job */ 34738032Speter if (tTd(50, 8)) 34838032Speter printf("dropenvelope(%s): unlocking job\n", id); 34938032Speter closexscript(e); 35038032Speter unlockqueue(e); 35138032Speter 35238032Speter /* make sure that this envelope is marked unused */ 35338032Speter if (e->e_dfp != NULL) 35438032Speter (void) xfclose(e->e_dfp, "dropenvelope df", e->e_id); 35538032Speter e->e_dfp = NULL; 35638032Speter e->e_id = NULL; 35738032Speter e->e_flags &= ~EF_HAS_DF; 35838032Speter} 35938032Speter/* 36038032Speter** CLEARENVELOPE -- clear an envelope without unlocking 36138032Speter** 36238032Speter** This is normally used by a child process to get a clean 36338032Speter** envelope without disturbing the parent. 36438032Speter** 36538032Speter** Parameters: 36638032Speter** e -- the envelope to clear. 36738032Speter** fullclear - if set, the current envelope is total 36838032Speter** garbage and should be ignored; otherwise, 36938032Speter** release any resources it may indicate. 37038032Speter** 37138032Speter** Returns: 37238032Speter** none. 37338032Speter** 37438032Speter** Side Effects: 37538032Speter** Closes files associated with the envelope. 37638032Speter** Marks the envelope as unallocated. 37738032Speter*/ 37838032Speter 37938032Spetervoid 38038032Speterclearenvelope(e, fullclear) 38138032Speter register ENVELOPE *e; 38238032Speter bool fullclear; 38338032Speter{ 38438032Speter register HDR *bh; 38538032Speter register HDR **nhp; 38638032Speter extern ENVELOPE BlankEnvelope; 38738032Speter 38838032Speter if (!fullclear) 38938032Speter { 39038032Speter /* clear out any file information */ 39138032Speter if (e->e_xfp != NULL) 39238032Speter (void) xfclose(e->e_xfp, "clearenvelope xfp", e->e_id); 39338032Speter if (e->e_dfp != NULL) 39438032Speter (void) xfclose(e->e_dfp, "clearenvelope dfp", e->e_id); 39538032Speter e->e_xfp = e->e_dfp = NULL; 39638032Speter } 39738032Speter 39838032Speter /* now clear out the data */ 39938032Speter STRUCTCOPY(BlankEnvelope, *e); 40038032Speter e->e_message = NULL; 40138032Speter if (Verbose) 40238032Speter e->e_sendmode = SM_DELIVER; 40338032Speter bh = BlankEnvelope.e_header; 40438032Speter nhp = &e->e_header; 40538032Speter while (bh != NULL) 40638032Speter { 40738032Speter *nhp = (HDR *) xalloc(sizeof *bh); 40838032Speter bcopy((char *) bh, (char *) *nhp, sizeof *bh); 40938032Speter bh = bh->h_link; 41038032Speter nhp = &(*nhp)->h_link; 41138032Speter } 41238032Speter} 41338032Speter/* 41438032Speter** INITSYS -- initialize instantiation of system 41538032Speter** 41638032Speter** In Daemon mode, this is done in the child. 41738032Speter** 41838032Speter** Parameters: 41938032Speter** none. 42038032Speter** 42138032Speter** Returns: 42238032Speter** none. 42338032Speter** 42438032Speter** Side Effects: 42538032Speter** Initializes the system macros, some global variables, 42638032Speter** etc. In particular, the current time in various 42738032Speter** forms is set. 42838032Speter*/ 42938032Speter 43038032Spetervoid 43138032Speterinitsys(e) 43238032Speter register ENVELOPE *e; 43338032Speter{ 43438032Speter char cbuf[5]; /* holds hop count */ 43538032Speter char pbuf[10]; /* holds pid */ 43638032Speter#ifdef TTYNAME 43738032Speter static char ybuf[60]; /* holds tty id */ 43838032Speter register char *p; 43938032Speter extern char *ttyname(); 44038032Speter#endif /* TTYNAME */ 44138032Speter extern void settime __P((ENVELOPE *)); 44238032Speter 44338032Speter /* 44438032Speter ** Give this envelope a reality. 44538032Speter ** I.e., an id, a transcript, and a creation time. 44638032Speter */ 44738032Speter 44838032Speter openxscript(e); 44938032Speter e->e_ctime = curtime(); 45038032Speter 45138032Speter /* 45238032Speter ** Set OutChannel to something useful if stdout isn't it. 45338032Speter ** This arranges that any extra stuff the mailer produces 45438032Speter ** gets sent back to the user on error (because it is 45538032Speter ** tucked away in the transcript). 45638032Speter */ 45738032Speter 45838032Speter if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) && 45938032Speter e->e_xfp != NULL) 46038032Speter OutChannel = e->e_xfp; 46138032Speter 46238032Speter /* 46338032Speter ** Set up some basic system macros. 46438032Speter */ 46538032Speter 46638032Speter /* process id */ 46738032Speter (void) snprintf(pbuf, sizeof pbuf, "%d", getpid()); 46838032Speter define('p', newstr(pbuf), e); 46938032Speter 47038032Speter /* hop count */ 47138032Speter (void) snprintf(cbuf, sizeof cbuf, "%d", e->e_hopcount); 47238032Speter define('c', newstr(cbuf), e); 47338032Speter 47438032Speter /* time as integer, unix time, arpa time */ 47538032Speter settime(e); 47638032Speter 47738032Speter#ifdef TTYNAME 47838032Speter /* tty name */ 47938032Speter if (macvalue('y', e) == NULL) 48038032Speter { 48138032Speter p = ttyname(2); 48238032Speter if (p != NULL) 48338032Speter { 48438032Speter if (strrchr(p, '/') != NULL) 48538032Speter p = strrchr(p, '/') + 1; 48638032Speter snprintf(ybuf, sizeof ybuf, "%s", p); 48738032Speter define('y', ybuf, e); 48838032Speter } 48938032Speter } 49038032Speter#endif /* TTYNAME */ 49138032Speter} 49238032Speter/* 49338032Speter** SETTIME -- set the current time. 49438032Speter** 49538032Speter** Parameters: 49638032Speter** none. 49738032Speter** 49838032Speter** Returns: 49938032Speter** none. 50038032Speter** 50138032Speter** Side Effects: 50238032Speter** Sets the various time macros -- $a, $b, $d, $t. 50338032Speter*/ 50438032Speter 50538032Spetervoid 50638032Spetersettime(e) 50738032Speter register ENVELOPE *e; 50838032Speter{ 50938032Speter register char *p; 51038032Speter auto time_t now; 51138032Speter char tbuf[20]; /* holds "current" time */ 51238032Speter char dbuf[30]; /* holds ctime(tbuf) */ 51338032Speter register struct tm *tm; 51438032Speter extern struct tm *gmtime(); 51538032Speter 51638032Speter now = curtime(); 51738032Speter tm = gmtime(&now); 51838032Speter (void) snprintf(tbuf, sizeof tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900, 51938032Speter tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); 52038032Speter define('t', newstr(tbuf), e); 52138032Speter (void) strcpy(dbuf, ctime(&now)); 52238032Speter p = strchr(dbuf, '\n'); 52338032Speter if (p != NULL) 52438032Speter *p = '\0'; 52538032Speter define('d', newstr(dbuf), e); 52638032Speter p = arpadate(dbuf); 52738032Speter p = newstr(p); 52838032Speter if (macvalue('a', e) == NULL) 52938032Speter define('a', p, e); 53038032Speter define('b', p, e); 53138032Speter} 53238032Speter/* 53338032Speter** OPENXSCRIPT -- Open transcript file 53438032Speter** 53538032Speter** Creates a transcript file for possible eventual mailing or 53638032Speter** sending back. 53738032Speter** 53838032Speter** Parameters: 53938032Speter** e -- the envelope to create the transcript in/for. 54038032Speter** 54138032Speter** Returns: 54238032Speter** none 54338032Speter** 54438032Speter** Side Effects: 54538032Speter** Creates the transcript file. 54638032Speter*/ 54738032Speter 54838032Speter#ifndef O_APPEND 54938032Speter#define O_APPEND 0 55038032Speter#endif 55138032Speter 55238032Spetervoid 55338032Speteropenxscript(e) 55438032Speter register ENVELOPE *e; 55538032Speter{ 55638032Speter register char *p; 55738032Speter int fd; 55838032Speter 55938032Speter if (e->e_xfp != NULL) 56038032Speter return; 56138032Speter p = queuename(e, 'x'); 56238032Speter fd = open(p, O_WRONLY|O_CREAT|O_APPEND, FileMode); 56338032Speter if (fd < 0) 56438032Speter { 56538032Speter syserr("Can't create transcript file %s", p); 56638032Speter fd = open("/dev/null", O_WRONLY, 0644); 56738032Speter if (fd < 0) 56838032Speter syserr("!Can't open /dev/null"); 56938032Speter } 57038032Speter e->e_xfp = fdopen(fd, "a"); 57138032Speter if (e->e_xfp == NULL) 57238032Speter syserr("!Can't create transcript stream %s", p); 57338032Speter#ifdef HASSETVBUF 57438032Speter setvbuf(e->e_xfp, NULL, _IOLBF, 0); 57538032Speter#else 57638032Speter setlinebuf(e->e_xfp); 57738032Speter#endif 57838032Speter if (tTd(46, 9)) 57938032Speter { 58038032Speter printf("openxscript(%s):\n ", p); 58138032Speter dumpfd(fileno(e->e_xfp), TRUE, FALSE); 58238032Speter } 58338032Speter} 58438032Speter/* 58538032Speter** CLOSEXSCRIPT -- close the transcript file. 58638032Speter** 58738032Speter** Parameters: 58838032Speter** e -- the envelope containing the transcript to close. 58938032Speter** 59038032Speter** Returns: 59138032Speter** none. 59238032Speter** 59338032Speter** Side Effects: 59438032Speter** none. 59538032Speter*/ 59638032Speter 59738032Spetervoid 59838032Speterclosexscript(e) 59938032Speter register ENVELOPE *e; 60038032Speter{ 60138032Speter if (e->e_xfp == NULL) 60238032Speter return; 60338032Speter (void) xfclose(e->e_xfp, "closexscript", e->e_id); 60438032Speter e->e_xfp = NULL; 60538032Speter} 60638032Speter/* 60738032Speter** SETSENDER -- set the person who this message is from 60838032Speter** 60938032Speter** Under certain circumstances allow the user to say who 61038032Speter** s/he is (using -f or -r). These are: 61138032Speter** 1. The user's uid is zero (root). 61238032Speter** 2. The user's login name is in an approved list (typically 61338032Speter** from a network server). 61438032Speter** 3. The address the user is trying to claim has a 61538032Speter** "!" character in it (since #2 doesn't do it for 61638032Speter** us if we are dialing out for UUCP). 61738032Speter** A better check to replace #3 would be if the 61838032Speter** effective uid is "UUCP" -- this would require me 61938032Speter** to rewrite getpwent to "grab" uucp as it went by, 62038032Speter** make getname more nasty, do another passwd file 62138032Speter** scan, or compile the UID of "UUCP" into the code, 62238032Speter** all of which are reprehensible. 62338032Speter** 62438032Speter** Assuming all of these fail, we figure out something 62538032Speter** ourselves. 62638032Speter** 62738032Speter** Parameters: 62838032Speter** from -- the person we would like to believe this message 62938032Speter** is from, as specified on the command line. 63038032Speter** e -- the envelope in which we would like the sender set. 63138032Speter** delimptr -- if non-NULL, set to the location of the 63238032Speter** trailing delimiter. 63338032Speter** delimchar -- the character that will delimit the sender 63438032Speter** address. 63538032Speter** internal -- set if this address is coming from an internal 63638032Speter** source such as an owner alias. 63738032Speter** 63838032Speter** Returns: 63938032Speter** none. 64038032Speter** 64138032Speter** Side Effects: 64238032Speter** sets sendmail's notion of who the from person is. 64338032Speter*/ 64438032Speter 64538032Spetervoid 64638032Spetersetsender(from, e, delimptr, delimchar, internal) 64738032Speter char *from; 64838032Speter register ENVELOPE *e; 64938032Speter char **delimptr; 65038032Speter int delimchar; 65138032Speter bool internal; 65238032Speter{ 65338032Speter register char **pvp; 65438032Speter char *realname = NULL; 65538032Speter register struct passwd *pw; 65638032Speter char *bp; 65738032Speter char buf[MAXNAME + 2]; 65838032Speter char pvpbuf[PSBUFSIZE]; 65938032Speter extern char *FullName; 66038032Speter 66138032Speter if (tTd(45, 1)) 66238032Speter printf("setsender(%s)\n", from == NULL ? "" : from); 66338032Speter 66438032Speter /* 66538032Speter ** Figure out the real user executing us. 66638032Speter ** Username can return errno != 0 on non-errors. 66738032Speter */ 66838032Speter 66938032Speter if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP || 67038032Speter OpMode == MD_ARPAFTP || OpMode == MD_DAEMON) 67138032Speter realname = from; 67238032Speter if (realname == NULL || realname[0] == '\0') 67338032Speter realname = username(); 67438032Speter 67538032Speter if (ConfigLevel < 2) 67638032Speter SuprErrs = TRUE; 67738032Speter 67838032Speter e->e_from.q_flags = QBADADDR; 67938032Speter if (from == NULL || 68038032Speter parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR, 68138032Speter delimchar, delimptr, e) == NULL || 68238032Speter bitset(QBADADDR, e->e_from.q_flags) || 68338032Speter e->e_from.q_mailer == ProgMailer || 68438032Speter e->e_from.q_mailer == FileMailer || 68538032Speter e->e_from.q_mailer == InclMailer) 68638032Speter { 68738032Speter /* log garbage addresses for traceback */ 68838032Speter if (from != NULL && LogLevel > 2) 68938032Speter { 69038032Speter char *p; 69138032Speter char ebuf[MAXNAME * 2 + 2]; 69238032Speter 69338032Speter p = macvalue('_', e); 69438032Speter if (p == NULL) 69538032Speter { 69638032Speter char *host = RealHostName; 69738032Speter 69838032Speter if (host == NULL) 69938032Speter host = MyHostName; 70038032Speter (void) snprintf(ebuf, sizeof ebuf, "%.*s@%.*s", 70138032Speter MAXNAME, realname, 70238032Speter MAXNAME, host); 70338032Speter p = ebuf; 70438032Speter } 70538032Speter sm_syslog(LOG_NOTICE, e->e_id, 70638032Speter "setsender: %s: invalid or unparseable, received from %s", 70738032Speter shortenstring(from, 83), p); 70838032Speter } 70938032Speter if (from != NULL) 71038032Speter { 71138032Speter if (!bitset(QBADADDR, e->e_from.q_flags)) 71238032Speter { 71338032Speter /* it was a bogus mailer in the from addr */ 71438032Speter e->e_status = "5.1.7"; 71538032Speter usrerr("553 Invalid sender address"); 71638032Speter } 71738032Speter SuprErrs = TRUE; 71838032Speter } 71938032Speter if (from == realname || 72038032Speter parseaddr(from = newstr(realname), &e->e_from, 72138032Speter RF_COPYALL|RF_SENDERADDR, ' ', NULL, e) == NULL) 72238032Speter { 72338032Speter char nbuf[100]; 72438032Speter 72538032Speter SuprErrs = TRUE; 72638032Speter expand("\201n", nbuf, sizeof nbuf, e); 72738032Speter if (parseaddr(from = newstr(nbuf), &e->e_from, 72838032Speter RF_COPYALL, ' ', NULL, e) == NULL && 72938032Speter parseaddr(from = "postmaster", &e->e_from, 73038032Speter RF_COPYALL, ' ', NULL, e) == NULL) 73138032Speter syserr("553 setsender: can't even parse postmaster!"); 73238032Speter } 73338032Speter } 73438032Speter else 73538032Speter FromFlag = TRUE; 73638032Speter e->e_from.q_flags |= QDONTSEND; 73738032Speter if (tTd(45, 5)) 73838032Speter { 73938032Speter printf("setsender: QDONTSEND "); 74038032Speter printaddr(&e->e_from, FALSE); 74138032Speter } 74238032Speter SuprErrs = FALSE; 74338032Speter 74438032Speter# if USERDB 74538032Speter if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags)) 74638032Speter { 74738032Speter register char *p; 74838032Speter extern char *udbsender __P((char *)); 74938032Speter 75038032Speter p = udbsender(e->e_from.q_user); 75138032Speter if (p != NULL) 75238032Speter from = p; 75338032Speter } 75438032Speter# endif /* USERDB */ 75538032Speter 75638032Speter if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags)) 75738032Speter { 75838032Speter if (!internal) 75938032Speter { 76038032Speter /* if the user already given fullname don't redefine */ 76138032Speter if (FullName == NULL) 76238032Speter FullName = macvalue('x', e); 76338032Speter if (FullName != NULL && FullName[0] == '\0') 76438032Speter FullName = NULL; 76538032Speter } 76638032Speter 76738032Speter if (e->e_from.q_user[0] != '\0' && 76838032Speter (pw = sm_getpwnam(e->e_from.q_user)) != NULL) 76938032Speter { 77038032Speter /* 77138032Speter ** Process passwd file entry. 77238032Speter */ 77338032Speter 77438032Speter /* extract home directory */ 77538032Speter if (strcmp(pw->pw_dir, "/") == 0) 77638032Speter e->e_from.q_home = newstr(""); 77738032Speter else 77838032Speter e->e_from.q_home = newstr(pw->pw_dir); 77938032Speter define('z', e->e_from.q_home, e); 78038032Speter 78138032Speter /* extract user and group id */ 78238032Speter e->e_from.q_uid = pw->pw_uid; 78338032Speter e->e_from.q_gid = pw->pw_gid; 78438032Speter e->e_from.q_flags |= QGOODUID; 78538032Speter 78638032Speter /* extract full name from passwd file */ 78738032Speter if (FullName == NULL && pw->pw_gecos != NULL && 78838032Speter strcmp(pw->pw_name, e->e_from.q_user) == 0 && 78938032Speter !internal) 79038032Speter { 79138032Speter buildfname(pw->pw_gecos, e->e_from.q_user, buf, sizeof buf); 79238032Speter if (buf[0] != '\0') 79338032Speter FullName = newstr(buf); 79438032Speter } 79538032Speter } 79638032Speter else 79738032Speter { 79838032Speter e->e_from.q_home = "/no/such/directory"; 79938032Speter } 80038032Speter if (FullName != NULL && !internal) 80138032Speter define('x', FullName, e); 80238032Speter } 80338032Speter else if (!internal && OpMode != MD_DAEMON) 80438032Speter { 80538032Speter if (e->e_from.q_home == NULL) 80638032Speter { 80738032Speter e->e_from.q_home = getenv("HOME"); 80838032Speter if (e->e_from.q_home != NULL && 80938032Speter strcmp(e->e_from.q_home, "/") == 0) 81038032Speter e->e_from.q_home++; 81138032Speter } 81238032Speter e->e_from.q_uid = RealUid; 81338032Speter e->e_from.q_gid = RealGid; 81438032Speter e->e_from.q_flags |= QGOODUID; 81538032Speter } 81638032Speter 81738032Speter /* 81838032Speter ** Rewrite the from person to dispose of possible implicit 81938032Speter ** links in the net. 82038032Speter */ 82138032Speter 82238032Speter pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL, NULL); 82338032Speter if (pvp == NULL) 82438032Speter { 82538032Speter /* don't need to give error -- prescan did that already */ 82638032Speter if (LogLevel > 2) 82738032Speter sm_syslog(LOG_NOTICE, e->e_id, 82838032Speter "cannot prescan from (%s)", 82938032Speter shortenstring(from, MAXSHORTSTR)); 83038032Speter finis(); 83138032Speter } 83238032Speter (void) rewrite(pvp, 3, 0, e); 83338032Speter (void) rewrite(pvp, 1, 0, e); 83438032Speter (void) rewrite(pvp, 4, 0, e); 83538032Speter bp = buf + 1; 83638032Speter cataddr(pvp, NULL, bp, sizeof buf - 2, '\0'); 83738032Speter if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags)) 83838032Speter { 83938032Speter /* heuristic: route-addr: add angle brackets */ 84038032Speter strcat(bp, ">"); 84138032Speter *--bp = '<'; 84238032Speter } 84338032Speter e->e_sender = newstr(bp); 84438032Speter define('f', e->e_sender, e); 84538032Speter 84638032Speter /* save the domain spec if this mailer wants it */ 84738032Speter if (e->e_from.q_mailer != NULL && 84838032Speter bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags)) 84938032Speter { 85038032Speter char **lastat; 85138032Speter extern char **copyplist __P((char **, bool)); 85238032Speter 85338032Speter /* get rid of any pesky angle brackets */ 85438032Speter (void) rewrite(pvp, 3, 0, e); 85538032Speter (void) rewrite(pvp, 1, 0, e); 85638032Speter (void) rewrite(pvp, 4, 0, e); 85738032Speter 85838032Speter /* strip off to the last "@" sign */ 85938032Speter for (lastat = NULL; *pvp != NULL; pvp++) 86038032Speter if (strcmp(*pvp, "@") == 0) 86138032Speter lastat = pvp; 86238032Speter if (lastat != NULL) 86338032Speter { 86438032Speter e->e_fromdomain = copyplist(lastat, TRUE); 86538032Speter if (tTd(45, 3)) 86638032Speter { 86738032Speter printf("Saving from domain: "); 86838032Speter printav(e->e_fromdomain); 86938032Speter } 87038032Speter } 87138032Speter } 87238032Speter} 87338032Speter/* 87438032Speter** PRINTENVFLAGS -- print envelope flags for debugging 87538032Speter** 87638032Speter** Parameters: 87738032Speter** e -- the envelope with the flags to be printed. 87838032Speter** 87938032Speter** Returns: 88038032Speter** none. 88138032Speter*/ 88238032Speter 88338032Speterstruct eflags 88438032Speter{ 88538032Speter char *ef_name; 88638032Speter u_long ef_bit; 88738032Speter}; 88838032Speter 88938032Speterstruct eflags EnvelopeFlags[] = 89038032Speter{ 89138032Speter { "OLDSTYLE", EF_OLDSTYLE }, 89238032Speter { "INQUEUE", EF_INQUEUE }, 89338032Speter { "NO_BODY_RETN", EF_NO_BODY_RETN }, 89438032Speter { "CLRQUEUE", EF_CLRQUEUE }, 89538032Speter { "SENDRECEIPT", EF_SENDRECEIPT }, 89638032Speter { "FATALERRS", EF_FATALERRS }, 89738032Speter { "DELETE_BCC", EF_DELETE_BCC }, 89838032Speter { "RESPONSE", EF_RESPONSE }, 89938032Speter { "RESENT", EF_RESENT }, 90038032Speter { "VRFYONLY", EF_VRFYONLY }, 90138032Speter { "WARNING", EF_WARNING }, 90238032Speter { "QUEUERUN", EF_QUEUERUN }, 90338032Speter { "GLOBALERRS", EF_GLOBALERRS }, 90438032Speter { "PM_NOTIFY", EF_PM_NOTIFY }, 90538032Speter { "METOO", EF_METOO }, 90638032Speter { "LOGSENDER", EF_LOGSENDER }, 90738032Speter { "NORECEIPT", EF_NORECEIPT }, 90838032Speter { "HAS8BIT", EF_HAS8BIT }, 90938032Speter { "NL_NOT_EOL", EF_NL_NOT_EOL }, 91038032Speter { "CRLF_NOT_EOL", EF_CRLF_NOT_EOL }, 91138032Speter { "RET_PARAM", EF_RET_PARAM }, 91238032Speter { "HAS_DF", EF_HAS_DF }, 91338032Speter { "IS_MIME", EF_IS_MIME }, 91438032Speter { "DONT_MIME", EF_DONT_MIME }, 91538032Speter { NULL } 91638032Speter}; 91738032Speter 91838032Spetervoid 91938032Speterprintenvflags(e) 92038032Speter register ENVELOPE *e; 92138032Speter{ 92238032Speter register struct eflags *ef; 92338032Speter bool first = TRUE; 92438032Speter 92538032Speter printf("%lx", e->e_flags); 92638032Speter for (ef = EnvelopeFlags; ef->ef_name != NULL; ef++) 92738032Speter { 92838032Speter if (!bitset(ef->ef_bit, e->e_flags)) 92938032Speter continue; 93038032Speter if (first) 93138032Speter printf("<%s", ef->ef_name); 93238032Speter else 93338032Speter printf(",%s", ef->ef_name); 93438032Speter first = FALSE; 93538032Speter } 93638032Speter if (!first) 93738032Speter printf(">\n"); 93838032Speter} 939