|
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 e
Length: 18666 (0x48ea) Types: TextFile Names: »envelope.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/envelope.c,v«
head 5.22; branch 5.22.0; access; symbols UICSO:5.22.0 VANILLA:5.22; locks; strict; comment @ * @; 5.22 date 90.06.20.08.35.46; author paul; state Exp; branches 5.22.0.1; next ; 5.22.0.1 date 90.06.21.13.47.56; author paul; state Exp; branches; next 5.22.0.2; 5.22.0.2 date 90.07.09.10.18.41; author paul; state Exp; branches; next 5.22.0.3; 5.22.0.3 date 90.10.16.11.26.36; author paul; state Exp; branches; next 5.22.0.4; 5.22.0.4 date 90.11.13.14.33.17; author paul; state Exp; branches; next 5.22.0.5; 5.22.0.5 date 90.11.24.21.45.27; author paul; state Exp; branches; next 5.22.0.6; 5.22.0.6 date 91.01.19.19.26.02; author paul; state Exp; branches; next 5.22.0.7; 5.22.0.7 date 91.02.17.04.13.28; author paul; state Exp; branches; next 5.22.0.8; 5.22.0.8 date 91.03.04.21.48.23; author paul; state Exp; branches; next ; desc @@ 5.22 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[] = "@@(#)envelope.c 5.22 (Berkeley) 6/1/90"; #endif /* not lint */ #include <sys/types.h> #include <sys/time.h> #include <sys/stat.h> #include <pwd.h> #include <sys/file.h> #include "sendmail.h" /* ** NEWENVELOPE -- allocate a new envelope ** ** Supports inheritance. ** ** Parameters: ** e -- the new envelope to fill in. ** ** Returns: ** e. ** ** Side Effects: ** none. */ ENVELOPE * newenvelope(e) register ENVELOPE *e; { register ENVELOPE *parent; extern putheader(), putbody(); extern ENVELOPE BlankEnvelope; parent = CurEnv; if (e == CurEnv) parent = e->e_parent; clearenvelope(e, TRUE); if (e == CurEnv) bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from); else bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from); e->e_parent = parent; e->e_ctime = curtime(); e->e_msgpriority = parent->e_msgsize; e->e_puthdr = putheader; e->e_putbody = putbody; if (CurEnv->e_xfp != NULL) (void) fflush(CurEnv->e_xfp); return (e); } \f /* ** DROPENVELOPE -- deallocate an envelope. ** ** Parameters: ** e -- the envelope to deallocate. ** ** Returns: ** none. ** ** Side Effects: ** housekeeping necessary to dispose of an envelope. ** Unlocks this queue file. */ dropenvelope(e) register ENVELOPE *e; { bool queueit = FALSE; register ADDRESS *q; if (tTd(50, 1)) { printf("dropenvelope %x id=", e); xputs(e->e_id); printf(" flags=%o\n", e->e_flags); } #ifdef LOG if (LogLevel > 10) syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=%o, pid=%d", e->e_id == NULL ? "(none)" : e->e_id, e->e_flags, getpid()); #endif LOG /* we must have an id to remove disk files */ if (e->e_id == NULL) return; /* ** Extract state information from dregs of send list. */ for (q = e->e_sendqueue; q != NULL; q = q->q_next) { if (bitset(QQUEUEUP, q->q_flags)) queueit = TRUE; } /* ** Send back return receipts as requested. */ if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)) { auto ADDRESS *rlist = NULL; sendtolist(CurEnv->e_receiptto, (ADDRESS *) NULL, &rlist); (void) returntosender("Return receipt", rlist, FALSE); } /* ** Arrange to send error messages if there are fatal errors. */ if (bitset(EF_FATALERRS|EF_TIMEOUT, e->e_flags) && ErrorMode != EM_QUIET) savemail(e); /* ** Instantiate or deinstantiate the queue. */ if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) || bitset(EF_CLRQUEUE, e->e_flags)) { if (e->e_df != NULL) xunlink(e->e_df); xunlink(queuename(e, 'q')); } else if (queueit || !bitset(EF_INQUEUE, e->e_flags)) { #ifdef QUEUE FILE *lockfp, *queueup(); lockfp = queueup(e, FALSE, FALSE); if (lockfp != NULL) (void) fclose(lockfp); #else QUEUE syserr("dropenvelope: queueup"); #endif QUEUE } /* now unlock the job */ closexscript(e); unlockqueue(e); /* make sure that this envelope is marked unused */ e->e_id = e->e_df = NULL; if (e->e_dfp != NULL) (void) fclose(e->e_dfp); e->e_dfp = NULL; } \f /* ** CLEARENVELOPE -- clear an envelope without unlocking ** ** This is normally used by a child process to get a clean ** envelope without disturbing the parent. ** ** Parameters: ** e -- the envelope to clear. ** fullclear - if set, the current envelope is total ** garbage and should be ignored; otherwise, ** release any resources it may indicate. ** ** Returns: ** none. ** ** Side Effects: ** Closes files associated with the envelope. ** Marks the envelope as unallocated. */ clearenvelope(e, fullclear) register ENVELOPE *e; bool fullclear; { register HDR *bh; register HDR **nhp; extern ENVELOPE BlankEnvelope; if (!fullclear) { /* clear out any file information */ if (e->e_xfp != NULL) (void) fclose(e->e_xfp); if (e->e_dfp != NULL) (void) fclose(e->e_dfp); } /* now clear out the data */ STRUCTCOPY(BlankEnvelope, *e); bh = BlankEnvelope.e_header; nhp = &e->e_header; while (bh != NULL) { *nhp = (HDR *) xalloc(sizeof *bh); bcopy((char *) bh, (char *) *nhp, sizeof *bh); bh = bh->h_link; nhp = &(*nhp)->h_link; } } \f /* ** INITSYS -- initialize instantiation of system ** ** In Daemon mode, this is done in the child. ** ** Parameters: ** none. ** ** Returns: ** none. ** ** Side Effects: ** Initializes the system macros, some global variables, ** etc. In particular, the current time in various ** forms is set. */ initsys() { static char cbuf[5]; /* holds hop count */ static char pbuf[10]; /* holds pid */ #ifdef TTYNAME static char ybuf[10]; /* holds tty id */ register char *p; #endif TTYNAME extern char *ttyname(); extern char *macvalue(); extern char Version[]; /* ** Give this envelope a reality. ** I.e., an id, a transcript, and a creation time. */ openxscript(CurEnv); CurEnv->e_ctime = curtime(); /* ** Set OutChannel to something useful if stdout isn't it. ** This arranges that any extra stuff the mailer produces ** gets sent back to the user on error (because it is ** tucked away in the transcript). */ if (OpMode == MD_DAEMON && QueueRun) OutChannel = CurEnv->e_xfp; /* ** Set up some basic system macros. */ /* process id */ (void) sprintf(pbuf, "%d", getpid()); define('p', pbuf, CurEnv); /* hop count */ (void) sprintf(cbuf, "%d", CurEnv->e_hopcount); define('c', cbuf, CurEnv); /* time as integer, unix time, arpa time */ settime(); #ifdef TTYNAME /* tty name */ if (macvalue('y', CurEnv) == NULL) { p = ttyname(2); if (p != NULL) { if (rindex(p, '/') != NULL) p = rindex(p, '/') + 1; (void) strcpy(ybuf, p); define('y', ybuf, CurEnv); } } #endif TTYNAME } \f /* ** SETTIME -- set the current time. ** ** Parameters: ** none. ** ** Returns: ** none. ** ** Side Effects: ** Sets the various time macros -- $a, $b, $d, $t. */ settime() { register char *p; auto time_t now; static char tbuf[20]; /* holds "current" time */ static char dbuf[30]; /* holds ctime(tbuf) */ register struct tm *tm; extern char *arpadate(); extern struct tm *gmtime(); extern char *macvalue(); now = curtime(); tm = gmtime(&now); (void) sprintf(tbuf, "%02d%02d%02d%02d%02d", tm->tm_year, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); define('t', tbuf, CurEnv); (void) strcpy(dbuf, ctime(&now)); *index(dbuf, '\n') = '\0'; if (macvalue('d', CurEnv) == NULL) define('d', dbuf, CurEnv); p = newstr(arpadate(dbuf)); if (macvalue('a', CurEnv) == NULL) define('a', p, CurEnv); define('b', p, CurEnv); } \f /* ** OPENXSCRIPT -- Open transcript file ** ** Creates a transcript file for possible eventual mailing or ** sending back. ** ** Parameters: ** e -- the envelope to create the transcript in/for. ** ** Returns: ** none ** ** Side Effects: ** Creates the transcript file. */ openxscript(e) register ENVELOPE *e; { register char *p; int fd; # ifdef LOG if (LogLevel > 19) syslog(LOG_DEBUG, "%s: openx%s", e->e_id, e->e_xfp == NULL ? "" : " (no)"); # endif LOG if (e->e_xfp != NULL) return; p = queuename(e, 'x'); fd = open(p, O_WRONLY|O_CREAT, 0644); if (fd < 0) syserr("Can't create %s", p); else e->e_xfp = fdopen(fd, "w"); } \f /* ** CLOSEXSCRIPT -- close the transcript file. ** ** Parameters: ** e -- the envelope containing the transcript to close. ** ** Returns: ** none. ** ** Side Effects: ** none. */ closexscript(e) register ENVELOPE *e; { if (e->e_xfp == NULL) return; (void) fclose(e->e_xfp); e->e_xfp = NULL; } \f /* ** SETSENDER -- set the person who this message is from ** ** Under certain circumstances allow the user to say who ** s/he is (using -f or -r). These are: ** 1. The user's uid is zero (root). ** 2. The user's login name is in an approved list (typically ** from a network server). ** 3. The address the user is trying to claim has a ** "!" character in it (since #2 doesn't do it for ** us if we are dialing out for UUCP). ** A better check to replace #3 would be if the ** effective uid is "UUCP" -- this would require me ** to rewrite getpwent to "grab" uucp as it went by, ** make getname more nasty, do another passwd file ** scan, or compile the UID of "UUCP" into the code, ** all of which are reprehensible. ** ** Assuming all of these fail, we figure out something ** ourselves. ** ** Parameters: ** from -- the person we would like to believe this message ** is from, as specified on the command line. ** ** Returns: ** none. ** ** Side Effects: ** sets sendmail's notion of who the from person is. */ setsender(from) char *from; { register char **pvp; char *realname = NULL; register struct passwd *pw; char buf[MAXNAME]; char pvpbuf[PSBUFSIZE]; extern struct passwd *getpwnam(); extern char *macvalue(); extern char **prescan(); extern bool safefile(); extern char *FullName; if (tTd(45, 1)) printf("setsender(%s)\n", from == NULL ? "" : from); /* ** Figure out the real user executing us. ** Username can return errno != 0 on non-errors. */ if (QueueRun || OpMode == MD_SMTP || OpMode == MD_ARPAFTP) realname = from; if (realname == NULL || realname[0] == '\0') { extern char *username(); realname = username(); } /* ** Determine if this real person is allowed to alias themselves. */ if (from != NULL) { extern bool trusteduser(); if (!trusteduser(realname) && getuid() != geteuid() && index(from, '!') == NULL && getuid() != 0) { /* network sends -r regardless (why why why?) */ /* syserr("%s, you cannot use the -f flag", realname); */ from = NULL; } } SuprErrs = TRUE; if (from == NULL || parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL) { /* log garbage addresses for traceback */ if (from != NULL) { # ifdef LOG if (LogLevel >= 1) if (realname == from && RealHostName != NULL) syslog(LOG_NOTICE, "from=%s unparseable, received from %s", from, RealHostName); else syslog(LOG_NOTICE, "Unparseable username %s wants from=%s", realname, from); # endif LOG } from = newstr(realname); if (parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL && parseaddr("postmaster", &CurEnv->e_from, 1, '\0') == NULL) { syserr("setsender: can't even parse postmaster!"); } } else FromFlag = TRUE; CurEnv->e_from.q_flags |= QDONTSEND; loweraddr(&CurEnv->e_from); SuprErrs = FALSE; if (CurEnv->e_from.q_mailer == LocalMailer && (pw = getpwnam(CurEnv->e_from.q_user)) != NULL) { /* ** Process passwd file entry. */ /* extract home directory */ CurEnv->e_from.q_home = newstr(pw->pw_dir); define('z', CurEnv->e_from.q_home, CurEnv); /* extract user and group id */ CurEnv->e_from.q_uid = pw->pw_uid; CurEnv->e_from.q_gid = pw->pw_gid; /* if the user has given fullname already, don't redefine */ if (FullName == NULL) FullName = macvalue('x', CurEnv); if (FullName != NULL && FullName[0] == '\0') FullName = NULL; /* extract full name from passwd file */ if (FullName == NULL && pw->pw_gecos != NULL && strcmp(pw->pw_name, CurEnv->e_from.q_user) == 0) { buildfname(pw->pw_gecos, CurEnv->e_from.q_user, buf); if (buf[0] != '\0') FullName = newstr(buf); } if (FullName != NULL) define('x', FullName, CurEnv); } else { if (CurEnv->e_from.q_home == NULL) CurEnv->e_from.q_home = getenv("HOME"); CurEnv->e_from.q_uid = getuid(); CurEnv->e_from.q_gid = getgid(); } /* ** Rewrite the from person to dispose of possible implicit ** links in the net. */ pvp = prescan(from, '\0', pvpbuf); if (pvp == NULL) { # ifdef LOG if (LogLevel >= 1) syslog(LOG_NOTICE, "cannot prescan from (%s)", from); # endif usrerr("cannot prescan from (%s)", from); finis(); } rewrite(pvp, 3); rewrite(pvp, 1); rewrite(pvp, 4); cataddr(pvp, buf, sizeof buf); define('f', newstr(buf), CurEnv); /* save the domain spec if this mailer wants it */ if (CurEnv->e_from.q_mailer != NULL && bitnset(M_CANONICAL, CurEnv->e_from.q_mailer->m_flags)) { extern char **copyplist(); while (*pvp != NULL && strcmp(*pvp, "@@") != 0) pvp++; if (*pvp != NULL) CurEnv->e_fromdomain = copyplist(pvp, TRUE); } } \f /* ** TRUSTEDUSER -- tell us if this user is to be trusted. ** ** Parameters: ** user -- the user to be checked. ** ** Returns: ** TRUE if the user is in an approved list. ** FALSE otherwise. ** ** Side Effects: ** none. */ bool trusteduser(user) char *user; { register char **ulist; extern char *TrustedUsers[]; for (ulist = TrustedUsers; *ulist != NULL; ulist++) if (strcmp(*ulist, user) == 0) return (TRUE); return (FALSE); } @ 5.22.0.1 log @Date: Wed, 20 Jun 90 15:39:37 -0400 (EDT) From: Craig_Everhart@@transarc.com To: paul@@uxc.cso.uiuc.edu (Paul Pomes - UofIllinois CSO) Subject: Re: Sendmail V5.64 + IDA enhancements available for anon-FTP Here's a sendmail patch for you that I've been sending around. I've been running it for years, and it was only when Peter Neumann had such trouble with RISKS duplications that I decided to try to propagate it. The problem addressed by the fix is that if sendmail delivers to a long address list (in a single request) but crashes in the middle, it has no record of the successful deliveries that it has made so far, so when it eventually gets around to retrying that request, it re-delivers to all the addresses to which it had been able to deliver earlier. Not only does this generate duplicate mail, but the re-delivery process also requires additional queue processing time, so that it might continue to take a long time even to attempt delivery to the last address in the list. The solution that this patch builds is simple and not very expensive: after every successful mail delivery, the qf* file is rewritten, omitting the recipient to whom delivery was successful. The qf* file gets shorter even as the request is processed. A crash in the middle of processing the list will result in duplicate delivery to at most one host. It doesn't require that much time to rewrite the qf* file; certainly less time than the delivery itself takes. The only real disadvantage I can imagine is that my sendmail sources have diverged in many ways from a UCB version of about 1986. Nonetheless, it shouldn't be difficult to install this change. As you can see, this change works by adding an additional flag parameter to queueup(), then calling queueup() (from sendall()) with this parameter set sometimes. The queueup() flag parameter controls which addresses are rewritten, looking at different flags. So here's the patch. I hope that you find it useful. I look forward to your reply. Thanks, Craig Everhart @ text @d154 1 a154 1 lockfp = queueup(e, FALSE, FALSE, FALSE); @ 5.22.0.2 log @Dropped re-write of queue file due to bug w. too many open files. This feature isn't too important for us. @ text @d154 1 a154 1 lockfp = queueup(e, FALSE, FALSE); @ 5.22.0.3 log @AIX, unlike the rest of the world, does not include time.h with sys/time.h. @ text @a26 3 #ifdef _IBMESA # include <time.h> #endif /* _IBMESA brain-damage */ @ 5.22.0.4 log @Changed _IBMESA to _AIX (provided in /etc/xlc.cfg). <sys/file.h> now included in sendmail.h. @ text @d27 1 a27 1 #ifdef _AIX d29 1 a29 1 #endif /* _AIX brain-damage */ d32 1 @ 5.22.0.5 log @Changed calls to parseaddr() to not pass constant strings. Commented out tokens following #else and #endif statements. @ text @d106 1 a106 1 #endif /* LOG */ d159 1 a159 1 #else /* !QUEUE */ d161 1 a161 1 #endif /* QUEUE */ d247 1 a247 1 #endif /* TTYNAME */ d298 1 a298 1 #endif /* TTYNAME */ d360 1 a360 1 #ifdef LOG d363 1 a363 1 #endif /* LOG */ a425 2 static char PostMaster[] = "postmaster"; /* for gcc */ d480 1 a480 1 #ifdef LOG d490 1 a490 1 #endif /* LOG */ d494 1 a494 1 parseaddr(PostMaster, &CurEnv->e_from, 1, '\0') == NULL) d554 1 a554 1 #ifdef LOG d557 1 a557 1 #endif /* LOG */ @ 5.22.0.6 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 1 a25 1 #include "sendmail.h" d32 1 @ 5.22.0.7 log @Added static keyword to declarations for closexscript() and trusteduser(). @ text @a92 1 static void closexscript(); a384 1 static void d464 1 a464 1 static bool trusteduser(); d594 1 a594 1 static bool @ 5.22.0.8 log @ANSIfied. @ text @a32 8 #ifdef __STDC__ static void closexscript(ENVELOPE *); static bool trusteduser(const char *); #else /* !__STDC__ */ static void closexscript(); static bool trusteduser(); #endif /* __STDC__ */ d53 1 a87 1 void d93 1 d155 1 a155 2 FILE *lockfp; a193 1 void a239 1 void d249 1 a312 1 void d320 3 a353 1 void a428 1 void d437 4 d454 3 d458 1 d466 2 d574 2 d598 1 a598 1 const char *user; @