* Copyright (c) 1983 Eric P. Allman
* Copyright (c) 1988 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)envelope.c 5.22 (Berkeley) 6/1/90";
** NEWENVELOPE -- allocate a new envelope
** e -- the new envelope to fill in.
register ENVELOPE
*parent
;
extern putheader(), putbody();
extern ENVELOPE BlankEnvelope
;
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
);
syslog(LOG_DEBUG
, "dropenvelope, id=%s, flags=%o, pid=%d",
e
->e_id
== NULL
? "(none)" : e
->e_id
,
/* we must have an id to remove disk files */
** 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
;
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
)
** 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
))
FILE *lockfp
, *queueup();
lockfp
= queueup(e
, FALSE
, FALSE
);
syserr("dropenvelope: queueup");
/* make sure that this envelope is marked unused */
e
->e_id
= e
->e_df
= NULL
;
** 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 */
/* now clear out the data */
STRUCTCOPY(BlankEnvelope
, *e
);
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
[10]; /* holds tty id */
** Give this envelope a reality.
** I.e., an id, a transcript, and a creation time.
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.
(void) sprintf(pbuf
, "%d", getpid());
define('p', pbuf
, CurEnv
);
(void) sprintf(cbuf
, "%d", CurEnv
->e_hopcount
);
define('c', cbuf
, CurEnv
);
/* time as integer, unix time, arpa time */
if (macvalue('y', CurEnv
) == NULL
)
if (rindex(p
, '/') != NULL
)
define('y', ybuf
, CurEnv
);
** 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
, "%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
)
** 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.
syslog(LOG_DEBUG
, "%s: openx%s", e
->e_id
, e
->e_xfp
== NULL
? "" : " (no)");
fd
= open(p
, O_WRONLY
|O_CREAT
, 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.
** 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.
** sets sendmail's notion of who the from person is.
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 (QueueRun
|| OpMode
== MD_SMTP
|| OpMode
== MD_ARPAFTP
)
if (realname
== NULL
|| realname
[0] == '\0')
** Determine if this real person is allowed to alias themselves.
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); */
if (from
== NULL
|| parseaddr(from
, &CurEnv
->e_from
, 1, '\0') == NULL
)
/* log garbage addresses for traceback */
if (realname
== from
&& RealHostName
!= NULL
)
"from=%s unparseable, received from %s",
"Unparseable username %s wants from=%s",
if (parseaddr(from
, &CurEnv
->e_from
, 1, '\0') == NULL
&&
parseaddr("postmaster", &CurEnv
->e_from
, 1, '\0') == NULL
)
syserr("setsender: can't even parse postmaster!");
CurEnv
->e_from
.q_flags
|= QDONTSEND
;
loweraddr(&CurEnv
->e_from
);
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 */
FullName
= macvalue('x', CurEnv
);
if (FullName
!= NULL
&& FullName
[0] == '\0')
/* 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
);
define('x', FullName
, CurEnv
);
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
pvp
= prescan(from
, '\0', pvpbuf
);
syslog(LOG_NOTICE
, "cannot prescan from (%s)", from
);
usrerr("cannot prescan from (%s)", from
);
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)
CurEnv
->e_fromdomain
= copyplist(pvp
, TRUE
);
** TRUSTEDUSER -- tell us if this user is to be trusted.
** user -- the user to be checked.
** TRUE if the user is in an approved list.
extern char *TrustedUsers
[];
for (ulist
= TrustedUsers
; *ulist
!= NULL
; ulist
++)
if (strcmp(*ulist
, user
) == 0)