* Copyright (c) 1983 Eric P. Allman
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)envelope.c 8.1 (Berkeley) %G%";
** NEWENVELOPE -- allocate a new envelope
** e -- the new envelope to fill in.
** parent -- the envelope to be the parent of e.
register ENVELOPE
*parent
;
extern putheader(), putbody();
extern ENVELOPE BlankEnvelope
;
if (e
== parent
&& e
->e_parent
!= NULL
)
bcopy((char *) &NullAddress
, (char *) &e
->e_from
, sizeof e
->e_from
);
bcopy((char *) &CurEnv
->e_from
, (char *) &e
->e_from
, sizeof e
->e_from
);
e
->e_msgpriority
= parent
->e_msgsize
;
if (CurEnv
->e_xfp
!= NULL
)
(void) fflush(CurEnv
->e_xfp
);
** DROPENVELOPE -- deallocate an envelope.
** e -- the envelope to deallocate.
** housekeeping necessary to dispose of an envelope.
** Unlocks this queue file.
printf("dropenvelope %x: id=", e
);
printf(", flags=%o\n", e
->e_flags
);
/* we must have an id to remove disk files */
syslog(LOG_DEBUG
, "dropenvelope, id=%s, flags=%o, pid=%d",
id
, e
->e_flags
, getpid());
** 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
))
** Send back return receipts as requested.
if (e
->e_receiptto
!= NULL
&& bitset(EF_SENDRECEIPT
, e
->e_flags
))
auto ADDRESS
*rlist
= NULL
;
(void) sendtolist(e
->e_receiptto
, (ADDRESS
*) NULL
, &rlist
, e
);
(void) returntosender("Return receipt", rlist
, FALSE
, e
);
** Arrange to send error messages if there are fatal errors.
if (bitset(EF_FATALERRS
|EF_TIMEOUT
, e
->e_flags
) &&
e
->e_errormode
!= EM_QUIET
)
** Instantiate or deinstantiate the queue.
if ((!queueit
&& !bitset(EF_KEEPQUEUE
, e
->e_flags
)) ||
bitset(EF_CLRQUEUE
, e
->e_flags
))
xunlink(queuename(e
, 'q'));
else if (queueit
|| !bitset(EF_INQUEUE
, e
->e_flags
))
queueup(e
, FALSE
, FALSE
);
syserr("554 dropenvelope: queueup");
/* make sure that this envelope is marked unused */
(void) xfclose(e
->e_dfp
, "dropenvelope", e
->e_df
);
e
->e_id
= e
->e_df
= NULL
;
syslog(LOG_INFO
, "%s: done", id
);
** CLEARENVELOPE -- clear an envelope without unlocking
** This is normally used by a child process to get a clean
** envelope without disturbing the parent.
** 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.
** Closes files associated with the envelope.
** Marks the envelope as unallocated.
clearenvelope(e
, fullclear
)
extern ENVELOPE BlankEnvelope
;
/* clear out any file information */
(void) xfclose(e
->e_xfp
, "clearenvelope xfp", e
->e_id
);
(void) xfclose(e
->e_dfp
, "clearenvelope dfp", e
->e_df
);
e
->e_xfp
= e
->e_dfp
= NULL
;
/* now clear out the data */
STRUCTCOPY(BlankEnvelope
, *e
);
e
->e_sendmode
= SM_DELIVER
;
bh
= BlankEnvelope
.e_header
;
*nhp
= (HDR
*) xalloc(sizeof *bh
);
bcopy((char *) bh
, (char *) *nhp
, sizeof *bh
);
** INITSYS -- initialize instantiation of system
** In Daemon mode, this is done in the child.
** Initializes the system macros, some global variables,
** etc. In particular, the current time in various
static char cbuf
[5]; /* holds hop count */
static char pbuf
[10]; /* holds pid */
static char ybuf
[60]; /* holds tty id */
** Give this envelope a reality.
** I.e., an id, a transcript, and a creation time.
** 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
&& !bitset(EF_QUEUERUN
, e
->e_flags
) &&
** Set up some basic system macros.
(void) sprintf(pbuf
, "%d", getpid());
(void) sprintf(cbuf
, "%d", e
->e_hopcount
);
/* time as integer, unix time, arpa time */
if (macvalue('y', e
) == NULL
)
if (strrchr(p
, '/') != NULL
)
** SETTIME -- set the current time.
** Sets the various time macros -- $a, $b, $d, $t.
static char tbuf
[20]; /* holds "current" time */
static char dbuf
[30]; /* holds ctime(tbuf) */
extern struct tm
*gmtime();
(void) sprintf(tbuf
, "%04d%02d%02d%02d%02d", tm
->tm_year
+ 1900,
tm
->tm_mon
+1, tm
->tm_mday
, tm
->tm_hour
, tm
->tm_min
);
(void) strcpy(dbuf
, ctime(&now
));
p
= newstr(arpadate(dbuf
));
if (macvalue('a', e
) == NULL
)
** OPENXSCRIPT -- Open transcript file
** Creates a transcript file for possible eventual mailing or
** e -- the envelope to create the transcript in/for.
** Creates the transcript file.
fd
= open(p
, O_WRONLY
|O_CREAT
|O_APPEND
, 0644);
syserr("Can't create %s", p
);
e
->e_xfp
= fdopen(fd
, "w");
** CLOSEXSCRIPT -- close the transcript file.
** e -- the envelope containing the transcript to close.
(void) xfclose(e
->e_xfp
, "closexscript", e
->e_id
);
** 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
** from -- the person we would like to believe this message
** is from, as specified on the command line.
** e -- the envelope in which we would like the sender set.
** delimptr -- if non-NULL, set to the location of the
** internal -- set if this address is coming from an internal
** source such as an owner alias.
** sets sendmail's notion of who the from person is.
setsender(from
, e
, delimptr
, internal
)
register struct passwd
*pw
;
extern struct passwd
*getpwnam();
printf("setsender(%s)\n", from
== NULL
? "" : from
);
** Figure out the real user executing us.
** Username can return errno != 0 on non-errors.
if (bitset(EF_QUEUERUN
, e
->e_flags
) || OpMode
== MD_SMTP
)
if (realname
== NULL
|| realname
[0] == '\0')
delimchar
= internal
? '\0' : ' ';
parseaddr(from
, &e
->e_from
, 1, delimchar
, delimptr
, e
) == NULL
)
/* log garbage addresses for traceback */
if (from
!= NULL
&& LogLevel
> 2)
char ebuf
[MAXNAME
* 2 + 2];
char *host
= RealHostName
;
(void) sprintf(ebuf
, "%s@%s", realname
, host
);
"from=%s unparseable, received from %s",
parseaddr(from
= newstr(realname
), &e
->e_from
, 1, ' ', NULL
, e
) == NULL
)
if (parseaddr("postmaster", &e
->e_from
, 1, ' ', NULL
, e
) == NULL
)
syserr("553 setsender: can't even parse postmaster!");
e
->e_from
.q_flags
|= QDONTSEND
;
printf("setsender: QDONTSEND ");
printaddr(&e
->e_from
, FALSE
);
if (e
->e_from
.q_mailer
== LocalMailer
)
extern char *udbsender();
/* if the user has given fullname already, don't redefine */
FullName
= macvalue('x', e
);
if (FullName
!= NULL
&& FullName
[0] == '\0')
** We have an alternate address for the sender
pvp
= prescan(p
, '\0', pvpbuf
, NULL
);
if ((pw
= getpwnam(e
->e_from
.q_user
)) != NULL
)
** Process passwd file entry.
/* extract home directory */
e
->e_from
.q_home
= newstr(pw
->pw_dir
);
define('z', e
->e_from
.q_home
, e
);
/* extract user and group id */
e
->e_from
.q_uid
= pw
->pw_uid
;
e
->e_from
.q_gid
= pw
->pw_gid
;
/* extract full name from passwd file */
if (FullName
== NULL
&& pw
->pw_gecos
!= NULL
&&
strcmp(pw
->pw_name
, e
->e_from
.q_user
) == 0 &&
buildfname(pw
->pw_gecos
, e
->e_from
.q_user
, buf
);
if (FullName
!= NULL
&& !internal
)
define('x', FullName
, e
);
if (e
->e_from
.q_home
== NULL
)
e
->e_from
.q_home
= getenv("HOME");
e
->e_from
.q_uid
= getuid();
e
->e_from
.q_gid
= getgid();
** Rewrite the from person to dispose of possible implicit
pvp
= prescan(from
, '\0', pvpbuf
, NULL
);
/* don't need to give error -- prescan did that already */
syslog(LOG_NOTICE
, "cannot prescan from (%s)", from
);
(void) rewrite(pvp
, 3, e
);
(void) rewrite(pvp
, 1, e
);
(void) rewrite(pvp
, 4, e
);
cataddr(pvp
, NULL
, buf
, sizeof buf
, '\0');
e
->e_sender
= newstr(buf
);
define('f', e
->e_sender
, e
);
/* save the domain spec if this mailer wants it */
if (!internal
&& e
->e_from
.q_mailer
!= NULL
&&
bitnset(M_CANONICAL
, e
->e_from
.q_mailer
->m_flags
))
extern char **copyplist();
while (*pvp
!= NULL
&& strcmp(*pvp
, "@") != 0)
e
->e_fromdomain
= copyplist(pvp
, TRUE
);