=============================================================================
CA-95:02                         CERT Advisory
                                January 26, 1995
			  Vulnerabilities in /bin/mail
-----------------------------------------------------------------------------

This advisory supersedes CA-91:01a SunOS Mail Vulnerability and CA-91:13
Ultrix Mail Vulnerability.

There are vulnerabilities in some versions of /bin/mail. Section III below
provides vendor-specific information and an alternative to /bin/mail.

As we receive additional information relating to this advisory, we will place
it, along with any clarifications, in a CA-95:02.README file. CERT advisories
and their associated README files are available by anonymous FTP from
info.cert.org. We encourage you to check the README files regularly for
updates on advisories that relate to your site.

-----------------------------------------------------------------------------

I.   Description

     Some versions of /bin/mail based on BSD 4.3 UNIX are vulnerable 
     because of timing windows in the way /bin/mail uses publicly writable
     directories.

II.  Impact

     Local users (users that have an account on the system) can create 
     or modify root-owned files on the system and can thereby gain
     unauthorized root access.

III. Solutions

     Either install a patch from your vendor or replace /bin/mail with
     mail.local.

     A.  Obtain the appropriate patch from your vendor and install it
         according to the instructions included with the patch.

         Below is a summary of the vendors listed in the current version of 
         the CA-95:02.README file, and the status they have provided.  
         More complete information, including how to obtain patches, is
         provided in Appendix A of this advisory and reproduced in the README
         file associated with this advisory. We will update the README file
         as we receive more information from vendors.

         If your vendor's name is not on this list, please contact the vendor
         directly.

         Vendor or Source                   Status
         ----------------                   ------------
         Apple Computer, Inc.               not vulnerable
         Berkeley SW Design, Inc. (BSDI)    not vulnerable
         Data General Corp.                 not vulnerable      
         Digital Equipment Corp.            vulnerable, patches available
         FreeBSD                            not vulnerable
         Harris                             not vulnerable
         IBM                                not vulnerable 
         NetBSD                             not vulnerable
         NeXT, Inc.                         not vulnerable 
         Pyramid                            not vulnerable
         The Santa Cruz Operation (SCO)     see note in Appendix A
         Solbourne (Grumman)                vulnerable - contact vendor
         Sun Microsystems, Inc.             SunOS 4.x vulnerable, patches
                                              available, patch revisions
                                              coming soon
                                            Solaris 2.x not vulnerable

     B. Replace /bin/mail with mail.local.

        If you cannot obtain a vendor-supplied replacement for /bin/mail, the
        CERT Coordination Center recommends using mail.local as a replacement
        for /bin/mail.

        Although the current version of mail.local is not a perfect solution,
        it addresses the vulnerabilities currently being exploited in
        /bin/mail. As improvements to mail.local become available, we will
        note them in the README file associated with this advisory. 

        The current version of mail.local has been tested on SunOS 4.1
        and Ultrix 4.X systems.

        Mail.local.c for BSD 4.3 systems, along with a README file containing
        installation instructions, can be found on the anonymous FTP servers
        listed below. In addition, Appendix B of this advisory contains the
        the README file and Appendix C contains mail.local.c.  

    Location             Filename 
    --------             --------
    info.cert.org        /pub/tools/mail.local/mail.local.c
                         MD5  c0d64e740b42f6dc5cc54a2bc37c31b0

    coast.cs.purdue.edu  /pub/tools/unix/mail.local/mail.local.c
                         MD5  c0d64e740b42f6dc5cc54a2bc37c31b0
    
---------------------------------------------------------------------------
The CERT Coordination Center thanks Eric Allman, Wolfgang Ley, Karl
Strickland, Wietse Venema, and Neil Woods for their contributions to
mail.local.
---------------------------------------------------------------------------

If you believe that your system has been compromised, contact the CERT
Coordination Center or your representative in Forum of Incident
Response and Security Teams (FIRST).

If you wish to send sensitive incident or vulnerability information to
CERT staff by electronic mail, we strongly advise that the e-mail be
encrypted.  The CERT Coordination Center can support a shared DES key, PGP
(public key available via anonymous FTP on info.cert.org), or PEM (contact
CERT staff for details).

Internet E-mail: cert@cert.org
Telephone: +1 412-268-7090 (24-hour hotline)
           CERT personnel answer 8:30 a.m.-5:00 p.m. EST(GMT-5)/EDT(GMT-4),
           and are on call for emergencies during other hours.
Fax: +1 412-268-6989

CERT Coordination Center
Software Engineering Institute
Carnegie Mellon University
Pittsburgh, PA 15213-3890
USA

Past advisories, CERT bulletins, information about FIRST representatives, 
and other information related to computer security are available for anonymous
FTP from info.cert.org.


CERT is a service mark of Carnegie Mellon University.


...............................................................................
Appendix A: Vendor Information
Current as of January 26, 1995
See CA-95.02.README for updated information

Below is information we have received from vendors who have patches available
or upcoming for the vulnerabilities described in this advisory, as well as
vendors who have confirmed that their products are not vulnerable. If your
vendor's name is not in one of these lists, contact the vendor directly for
information on whether their version of sendmail is vulnerable and, if so, the
status of patches to address the vulnerabilities.

NOT VULNERABLE
--------------
The following vendors have reported that their products are NOT vulnerable.
         Apple Computer, Inc.               
         Berkeley SW Design, Inc. (BSDI)    
         Data General Corp.
         Harris                             
         IBM                                
         NeXT, Inc.                         
         Pyramid                            
         The Santa Cruz Operation (SCO) - not vulnerable, but see note below
         Sun Microsystems, Inc. - Solaris 2.x (SunOS 4.x is vulnerable; see
                                               below)  

In addition, we have reports that the following products are NOT vulnerable.
         FreeBSD                   
         NetBSD                    

VULNERABLE
----------
We have reports that the following vendors' products ARE vulnerable.
Patch information is provided below.

-----------------------------
Digital Equipment Corporation
 
Vulnerable:  DEC OSF/1 versions 1.2, 1.3, and 2.0
             DEC ULTRIX versions 4.3, 4.3A, and 4.4

Obtain and install the appropriate patch according to the instructions
included with the patch. The patch that corrects the /bin/mail problem in each
case is part of a comprehensive Security Enhanced Kit that addresses other
problems as well. This kit has been available since May 17, 1994. It is
described in DEC security advisory #0505 and in CERT bulletin VB-94:02.

        1. DEC OSF/1
	   Upgrade/install OSF/1 to a minimum of V2.0 and 
           install Security Enhanced Kit CSCPAT_4061 v1.0. 

        2. DEC ULTRIX
           Upgrade/install ULTRIX to a minimum of V4.4 and 
           install Security Enhanced Kit CSCPAT_4060 v1.0.
           
Both kits listed above are available from Digital Equipment Corporation by
contacting your normal Digital support channel or by request via DSNlink for
electronic transfer. 

-----------------------------
The Santa Cruz Operation (SCO)

SCO's version of /bin/mail is not vulnerable to the problems mentioned
in this advisory. SCO's /bin/mail is not setuid-root. However, SCO's 
/bin/mail has other security-related issues that are fixed by SCO's
Support Level Supplement (SLS) uod392a. To get this:

ftp:    ftp.sco.COM:/SLS/uod392a.Z      (compressed disk image)
        ftp.sco.COM:/SLS/uod392a.ltr.Z  (cover letter)
        ftp.sco.COM:/SLS/README

-----------------------------
Solbourne

Grumman System Support Corporation now performs all Solbourne
software and hardware support. Please contact them for further
information.
       
        ftp: ftp.nts.gssc.com
        phone: 1-800-447-2861
        e-mail: support@nts.gssc.com

-----------------------------
Sun Microsystems, Inc.
 
Current patches are listed below, but they are being revised.

        SunOS      Patch              MD5 Checksum       
        ------     -----              ------------
        4.1.3      100224-13.tar.Z    90a507017a1a40c4622b3f1f00ce5d2d
        4.1.3UI    101436-08.tar.Z    0e64560edc61eb4b3da81a932e8b11e1  

        The patches can be obtained from local Sun Answer Centers and
        through anonymous FTP from ftp.uu.net in the /systems/sun/sun-dist
        directory. In Europe, the patches are available from mcsun.eu.net 
        in the /sun/fixes directory. 


Appendix B: README File for mail.local.c

/bin/mail is a setuid root program with several security vulnerabilities.  If
you cannot obtain a vendor-supplied replacement for /bin/mail, the CERT
Coordination Center suggests using mail.local as a replacement for /bin/mail.

In the early days of UNIX, /bin/mail was used to read and to send e-mail.
Over the years, many users have switched to e-mail programs with better user
interfaces and more features.

On BSD 4.3 based UNIX systems using sendmail, /bin/mail is still being used
as the local delivery agent.  These systems could be at risk.  Systems based
on UNIX system III or system IV are not vulnerable.

mail.local is a replacement for the /bin/mail program.  It is only a
delivery agent for sendmail and does not have a user interface.  It is
distributed as a C source file.

For operating systems based on BSD 4.3, mail.local.c from a BSD 4.4
distribution will not compile.  The version of mail.local.c in this directory
was ported to BSD 4.3 by Eric Allman.  It should compile and operate on most
BSD 4.3 systems.  It has been tested on SunOS 4.1.x and Ultrix 4.x systems.

To install mail.local, edit the source file to set the _PATH_MAILDIR to the
directory where users' spooled mail files are located.  The default is
"/var/spool/mail".

SunOS
	% cc -Bstatic -O -o mail.local mail.local.c
Ultrix
	% cc -O -o mail.local mail.local.c -Dultrix

As root:

	# mv mail.local $INSTALL_DIR

		Substitute $INSTALL_DIR for the full pathname of the 
		directory where mail.local will be installed.

	# chown root $INSTALL_DIR/mail.local
	# chmod 4711 $INSTALL_DIR/mail.local

	Edit the sendmail.cf file (in /etc or /usr/lib) search for Mlocal.
	On that line, replace /bin/mail with $INSTALL_DIR/mail.local.
	Restart the sendmail process.  For versions of sendmail using
	frozen configuration files,  it is important to refreeze the
	configuration file before restarting the sendmail process.

	Test the e-mail system.  When you are satisfied that everything
	is working, disable the setuid root bit on the /bin/mail program.

	# chmod 0711 /bin/mail 
		OR
	# chmod 0711 /usr/bin/mail


  ****************************************************************************
  *   The CERT Coordination Center will not formally review, evaluate, or    *
  *   endorse the program described.  The decision to use the program        *
  *   described is the responsibility of each user or organization and we    *
  *   encourage each organization to thoroughly evaluate this program        *
  *   before installation or use.                                            *
  ****************************************************************************


Appendix C: mail.local.c

/*-
 * Copyright (c) 1990, 1993, 1994
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 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
 * SUCH DAMAGE.
 */

#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1990, 1993, 1994\n\
	The Regents of the University of California.  All rights reserved.\n";
#endif /* not lint */

#ifndef lint
static char sccsid[] = "@(#)mail.local.c	8.18 (Berkeley) 1/25/95";
#endif /* not lint */

/*
 * This is not intended to compile on System V derived systems
 * such as Solaris or HP-UX, since they use a totally different
 * approach to mailboxes (essentially, they have a setgid program
 * rather than setuid, and they rely on the ability to "give away"
 * files to do their work).  IT IS NOT A BUG that this doesn't
 * compile on such architectures.
 */

#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>

#include <netinet/in.h>

#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include <ctype.h>

#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#ifndef LOCK_EX
# include <sys/file.h>
#endif

#ifdef BSD4_4
# include "pathnames.h"
#endif

#ifndef __P
# ifdef __STDC__
#  define __P(protos)	protos
# else
#  define __P(protos)	()
#  define const
# endif
#endif
#ifndef __dead
# if defined(__GNUC__) && (__GNUC__ < 2 || __GNUC_MINOR__ < 5) && !defined(__STRICT_ANSI__)
#  define __dead	__volatile
# else
#  define __dead
# endif
#endif

#ifndef BSD4_4
# define _BSD_VA_LIST_	va_list
extern char	*strerror __P((int));
#endif

#ifndef _PATH_LOCTMP
# define _PATH_LOCTMP	"/tmp/local.XXXXXX"
#endif
#ifndef _PATH_MAILDIR
# define _PATH_MAILDIR	"/var/spool/mail"
#endif

#ifndef S_ISREG
# define S_ISREG(mode)	(((mode) & _S_IFMT) == S_IFREG)
#endif

int eval = EX_OK;			/* sysexits.h error value. */

void		deliver __P((int, char *));
void		e_to_sys __P((int));
__dead void	err __P((const char *, ...));
void		notifybiff __P((char *));
int		store __P((char *));
void		usage __P((void));
void		vwarn __P((const char *, _BSD_VA_LIST_));
void		warn __P((const char *, ...));

int
main(argc, argv)
	int argc;
	char *argv[];
{
	struct passwd *pw;
	int ch, fd;
	uid_t uid;
	char *from;
	extern char *optarg;
	extern int optind;

	/* make sure we have some open file descriptors */
	for (fd = 10; fd < 30; fd++)
		(void) close(fd);

	/* use a reasonable umask */
	(void) umask(0077);

#ifdef LOG_MAIL
	openlog("mail.local", 0, LOG_MAIL);
#else
	openlog("mail.local", 0);
#endif

	from = NULL;
	while ((ch = getopt(argc, argv, "df:r:")) != EOF)
		switch(ch) {
		case 'd':		/* Backward compatible. */
			break;
		case 'f':
		case 'r':		/* Backward compatible. */
			if (from != NULL) {
				warn("multiple -f options");
				usage();
			}
			from = optarg;
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	if (!*argv)
		usage();

	/*
	 * If from not specified, use the name from getlogin() if the
	 * uid matches, otherwise, use the name from the password file
	 * corresponding to the uid.
	 */
	uid = getuid();
	if (!from && (!(from = getlogin()) ||
	    !(pw = getpwnam(from)) || pw->pw_uid != uid))
		from = (pw = getpwuid(uid)) ? pw->pw_name : "???";

	/*
	 * There is no way to distinguish the error status of one delivery
	 * from the rest of the deliveries.  So, if we failed hard on one
	 * or more deliveries, but had no failures on any of the others, we
	 * return a hard failure.  If we failed temporarily on one or more
	 * deliveries, we return a temporary failure regardless of the other
	 * failures.  This results in the delivery being reattempted later
	 * at the expense of repeated failures and multiple deliveries.
	 */
	for (fd = store(from); *argv; ++argv)
		deliver(fd, *argv);
	exit(eval);
}

int
store(from)
	char *from;
{
	FILE *fp;
	time_t tval;
	int fd, eline;
	char line[2048];
	char tmpbuf[sizeof _PATH_LOCTMP + 1];

	strcpy(tmpbuf, _PATH_LOCTMP);
	if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL) {
		e_to_sys(errno);
		err("unable to open temporary file");
	}
	(void)unlink(tmpbuf);

	(void)time(&tval);
	(void)fprintf(fp, "From %s %s", from, ctime(&tval));

	line[0] = '\0';
	for (eline = 1; fgets(line, sizeof(line), stdin);) {
		if (line[0] == '\n')
			eline = 1;
		else {
			if (eline && line[0] == 'F' &&
			    !memcmp(line, "From ", 5))
				(void)putc('>', fp);
			eline = 0;
		}
		(void)fprintf(fp, "%s", line);
		if (ferror(fp)) {
			e_to_sys(errno);
			err("temporary file write error");
		}
	}

	/* If message not newline terminated, need an extra. */
	if (!strchr(line, '\n'))
		(void)putc('\n', fp);
	/* Output a newline; note, empty messages are allowed. */
	(void)putc('\n', fp);

	if (fflush(fp) == EOF || ferror(fp)) {
		e_to_sys(errno);
		err("temporary file write error");
	}
	return (fd);
}

void
deliver(fd, name)
	int fd;
	char *name;
{
	struct stat fsb, sb;
	struct passwd *pw;
	int mbfd, nr, nw, off;
	char *p;
	char biffmsg[100], buf[8*1024], path[MAXPATHLEN];
	off_t curoff;

	/*
	 * Disallow delivery to unknown names -- special mailboxes can be
	 * handled in the sendmail aliases file.
	 */
	if (!(pw = getpwnam(name))) {
		if (eval != EX_TEMPFAIL)
			eval = EX_UNAVAILABLE;
		warn("unknown name: %s", name);
		return;
	}

	/*
	 * Keep name reasonably short to avoid buffer overruns.
	 *	This isn't necessary on BSD because of the proper
	 *	definition of snprintf(), but it can cause problems
	 *	on other systems.
	 * Also, clear out any bogus characters.
	 */

	if (strlen(name) > 40)
		name[40] = '\0';
	for (p = name; *p != '\0'; p++)
	{
		if (!isascii(*p))
			*p &= 0x7f;
		else if (!isprint(*p))
			*p = '.';
	}

	(void)snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);

	/*
	 * If the mailbox is linked or a symlink, fail.  There's an obvious
	 * race here, that the file was replaced with a symbolic link after
	 * the lstat returned, but before the open.  We attempt to detect
	 * this by comparing the original stat information and information
	 * returned by an fstat of the file descriptor returned by the open.
	 *
	 * NB: this is a symptom of a larger problem, that the mail spooling
	 * directory is writeable by the wrong users.  If that directory is
	 * writeable, system security is compromised for other reasons, and
	 * it cannot be fixed here.
	 *
	 * If we created the mailbox, set the owner/group.  If that fails,
	 * just return.  Another process may have already opened it, so we
	 * can't unlink it.  Historically, binmail set the owner/group at
	 * each mail delivery.  We no longer do this, assuming that if the
	 * ownership or permissions were changed there was a reason.
	 *
	 * XXX
	 * open(2) should support flock'ing the file.
	 */
tryagain:
	lockmbox(path);
	if (lstat(path, &sb)) {
		mbfd = open(path,
		    O_APPEND|O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
		if (mbfd == -1) {
			if (errno == EEXIST)
				goto tryagain;
		} else if (fchown(mbfd, pw->pw_uid, pw->pw_gid)) {
			e_to_sys(errno);
			warn("chown %u.%u: %s", pw->pw_uid, pw->pw_gid, name);
			unlockmbox();
			return;
		}
	} else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) {
		e_to_sys(errno);
		warn("%s: irregular file", path);
		unlockmbox();
		return;
	} else if (sb.st_uid != pw->pw_uid) {
		warn("%s: wrong ownership (%d)", path, sb.st_uid);
		unlockmbox();
		return;
	} else {
		mbfd = open(path, O_APPEND|O_WRONLY, 0);
		if (mbfd != -1 &&
		    (fstat(mbfd, &fsb) || fsb.st_nlink != 1 ||
		    !S_ISREG(fsb.st_mode) || sb.st_dev != fsb.st_dev ||
		    sb.st_ino != fsb.st_ino || sb.st_uid != fsb.st_uid)) {
			warn("%s: file changed after open", path);
			(void)close(mbfd);
			unlockmbox();
			return;
		}
	}

	if (mbfd == -1) {
		e_to_sys(errno);
		warn("%s: %s", path, strerror(errno));
		unlockmbox();
		return;
	}

	/* Wait until we can get a lock on the file. */
	if (flock(mbfd, LOCK_EX)) {
		e_to_sys(errno);
		warn("%s: %s", path, strerror(errno));
		unlockmbox();
		goto err1;
	}

	/* Get the starting offset of the new message for biff. */
	curoff = lseek(mbfd, (off_t)0, SEEK_END);
	(void)snprintf(biffmsg, sizeof(biffmsg),
		sizeof curoff > sizeof(long) ? "%s@%qd\n" : "%s@%ld\n", 
		name, curoff);

	/* Copy the message into the file. */
	if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
		e_to_sys(errno);
		warn("temporary file: %s", strerror(errno));
		goto err1;
	}
	while ((nr = read(fd, buf, sizeof(buf))) > 0)
		for (off = 0; off < nr; off += nw)
			if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
				e_to_sys(errno);
				warn("%s: %s", path, strerror(errno));
				goto err2;;
			}
	if (nr < 0) {
		e_to_sys(errno);
		warn("temporary file: %s", strerror(errno));
		goto err2;;
	}

	/* Flush to disk, don't wait for update. */
	if (fsync(mbfd)) {
		e_to_sys(errno);
		warn("%s: %s", path, strerror(errno));
err2:		(void)ftruncate(mbfd, curoff);
err1:		(void)close(mbfd);
		unlockmbox();
		return;
	}
		
	/* Close and check -- NFS doesn't write until the close. */
	if (close(mbfd)) {
		e_to_sys(errno);
		warn("%s: %s", path, strerror(errno));
		unlockmbox();
		return;
	}

	unlockmbox();
	notifybiff(biffmsg);
}

/*
 * user.lock files are necessary for compatibility with other
 * systems, e.g., when the mail spool file is NFS exported.
 * Alas, mailbox locking is more than just a local matter.
 * EPA 11/94.
 */

char	lockname[MAXPATHLEN];
int	locked = 0;

lockmbox(path)
	char *path;
{
	int statfailed = 0;

	if (locked)
		return;
	sprintf(lockname, "%s.lock", path);
	for (;; sleep(5)) {
		int fd;
		struct stat st;
		time_t now;

		fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT, 0);
		if (fd >= 0) {
			locked = 1;
			close(fd);
			return;
		}
		if (stat(lockname, &st) < 0) {
			if (statfailed++ > 5)
				return;
			continue;
		}
		statfailed = 0;
		time(&now);
		if (now < st.st_ctime + 300)
			continue;
		unlink(lockname);
	}
}

unlockmbox()
{
	if (!locked)
		return;
	unlink(lockname);
	locked = 0;
}

void
notifybiff(msg)
	char *msg;
{
	static struct sockaddr_in addr;
	static int f = -1;
	struct hostent *hp;
	struct servent *sp;
	int len;

	if (!addr.sin_family) {
		/* Be silent if biff service not available. */
		if (!(sp = getservbyname("biff", "udp")))
			return;
		if (!(hp = gethostbyname("localhost"))) {
			warn("localhost: %s", strerror(errno));
			return;
		}
		addr.sin_family = hp->h_addrtype;
		memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
		addr.sin_port = sp->s_port;
	}
	if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		warn("socket: %s", strerror(errno));
		return;
	}
	len = strlen(msg) + 1;
	if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr))
	    != len)
		warn("sendto biff: %s", strerror(errno));
}

void
usage()
{
	eval = EX_USAGE;
	err("usage: mail.local [-f from] user ...");
}

#if __STDC__
void
err(const char *fmt, ...)
#else
void
err(fmt, va_alist)
	const char *fmt;
	va_dcl
#endif
{
	va_list ap;

#if __STDC__
	va_start(ap, fmt);
#else
	va_start(ap);
#endif
	vwarn(fmt, ap);
	va_end(ap);

	exit(eval);
}

void
#if __STDC__
warn(const char *fmt, ...)
#else
warn(fmt, va_alist)
	const char *fmt;
	va_dcl
#endif
{
	va_list ap;

#if __STDC__
	va_start(ap, fmt);
#else
	va_start(ap);
#endif
	vwarn(fmt, ap);
	va_end(ap);
}

void
vwarn(fmt, ap)
	const char *fmt;
	_BSD_VA_LIST_ ap;
{
	/*
	 * Log the message to stderr.
	 *
	 * Don't use LOG_PERROR as an openlog() flag to do this,
	 * it's not portable enough.
	 */
	if (eval != EX_USAGE)
		(void)fprintf(stderr, "mail.local: ");
	(void)vfprintf(stderr, fmt, ap);
	(void)fprintf(stderr, "\n");

#ifndef ultrix
	/* Log the message to syslog. */
	vsyslog(LOG_ERR, fmt, ap);
#else
	{
		char fmtbuf[10240];

		(void) sprintf(fmtbuf, fmt, ap);
		syslog(LOG_ERR, "%s", fmtbuf);
	}
#endif
}

/*
 * e_to_sys --
 *	Guess which errno's are temporary.  Gag me.
 */
void
e_to_sys(num)
	int num;
{
	/* Temporary failures override hard errors. */
	if (eval == EX_TEMPFAIL)
		return;

	switch(num) {		/* Hopefully temporary errors. */
#ifdef EAGAIN
	case EAGAIN:		/* Resource temporarily unavailable */
#endif
#ifdef EDQUOT
	case EDQUOT:		/* Disc quota exceeded */
#endif
#ifdef EBUSY
	case EBUSY:		/* Device busy */
#endif
#ifdef EPROCLIM
	case EPROCLIM:		/* Too many processes */
#endif
#ifdef EUSERS
	case EUSERS:		/* Too many users */
#endif
#ifdef ECONNABORTED
	case ECONNABORTED:	/* Software caused connection abort */
#endif
#ifdef ECONNREFUSED
	case ECONNREFUSED:	/* Connection refused */
#endif
#ifdef ECONNRESET
	case ECONNRESET:	/* Connection reset by peer */
#endif
#ifdef EDEADLK
	case EDEADLK:		/* Resource deadlock avoided */
#endif
#ifdef EFBIG
	case EFBIG:		/* File too large */
#endif
#ifdef EHOSTDOWN
	case EHOSTDOWN:		/* Host is down */
#endif
#ifdef EHOSTUNREACH
	case EHOSTUNREACH:	/* No route to host */
#endif
#ifdef EMFILE
	case EMFILE:		/* Too many open files */
#endif
#ifdef ENETDOWN
	case ENETDOWN:		/* Network is down */
#endif
#ifdef ENETRESET
	case ENETRESET:		/* Network dropped connection on reset */
#endif
#ifdef ENETUNREACH
	case ENETUNREACH:	/* Network is unreachable */
#endif
#ifdef ENFILE
	case ENFILE:		/* Too many open files in system */
#endif
#ifdef ENOBUFS
	case ENOBUFS:		/* No buffer space available */
#endif
#ifdef ENOMEM
	case ENOMEM:		/* Cannot allocate memory */
#endif
#ifdef ENOSPC
	case ENOSPC:		/* No space left on device */
#endif
#ifdef EROFS
	case EROFS:		/* Read-only file system */
#endif
#ifdef ESTALE
	case ESTALE:		/* Stale NFS file handle */
#endif
#ifdef ETIMEDOUT
	case ETIMEDOUT:		/* Connection timed out */
#endif
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK
	case EWOULDBLOCK:	/* Operation would block. */
#endif
		eval = EX_TEMPFAIL;
		break;
	default:
		eval = EX_UNAVAILABLE;
		break;
	}
}

#ifndef BSD4_4

char *
strerror(eno)
	int eno;
{
	extern int sys_nerr;
	extern char *sys_errlist[];
	static char ebuf[60];

	if (eno >= 0 && eno <= sys_nerr)
		return sys_errlist[eno];
	(void) sprintf(ebuf, "Error %d", eno);
	return ebuf;
}

#if __STDC__
snprintf(char *buf, int bufsiz, const char *fmt, ...)
#else
snprintf(buf, bufsiz, fmt, va_alist)
	char *buf;
	int bufsiz;
	const char *fmt;
	va_dcl
#endif
{
	va_list ap;

#if __STDC__
	va_start(ap, fmt);
#else
	va_start(ap);
#endif
	vsprintf(buf, fmt, ap);
	va_end(ap);
}

#endif

#ifdef ultrix

/*
 * Copyright (c) 1987, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 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
 * SUCH DAMAGE.
 */

#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)mktemp.c	8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>

static int _gettemp();

mkstemp(path)
	char *path;
{
	int fd;

	return (_gettemp(path, &fd) ? fd : -1);
}

/*
char *
mktemp(path)
	char *path;
{
	return(_gettemp(path, (int *)NULL) ? path : (char *)NULL);
}
*/

static
_gettemp(path, doopen)
	char *path;
	register int *doopen;
{
	extern int errno;
	register char *start, *trv;
	struct stat sbuf;
	u_int pid;

	pid = getpid();
	for (trv = path; *trv; ++trv);		/* extra X's get set to 0's */
	while (*--trv == 'X') {
		*trv = (pid % 10) + '0';
		pid /= 10;
	}

	/*
	 * check the target directory; if you have six X's and it
	 * doesn't exist this runs for a *very* long time.
	 */
	for (start = trv + 1;; --trv) {
		if (trv <= path)
			break;
		if (*trv == '/') {
			*trv = '\0';
			if (stat(path, &sbuf))
				return(0);
			if (!S_ISDIR(sbuf.st_mode)) {
				errno = ENOTDIR;
				return(0);
			}
			*trv = '/';
			break;
		}
	}

	for (;;) {
		if (doopen) {
			if ((*doopen =
			    open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
				return(1);
			if (errno != EEXIST)
				return(0);
		}
		else if (stat(path, &sbuf))
			return(errno == ENOENT ? 1 : 0);

		/* tricky little algorithm for backward compatibility */
		for (trv = start;;) {
			if (!*trv)
				return(0);
			if (*trv == 'z')
				*trv++ = 'a';
			else {
				if (isdigit(*trv))
					*trv = 'a';
				else
					++*trv;
				break;
			}
		}
	}
	/*NOTREACHED*/
}

#endif






