[36] in bugtraq

home help back first fref pref prev next nref lref last post

Earlier mail from the bugtraq mailing list... forwarded.

wchuang@ATHENA.MIT.EDU (wchuang@ATHENA.MIT.EDU)
Tue Oct 18 18:41:30 1994

Received: from PACIFIC-CARRIER-ANNEX.MIT.EDU by po6.MIT.EDU (5.61/4.7) id AA04518; Mon, 3 Oct 94 19:50:23 EDT
Received: from villa.fc.net by MIT.EDU with SMTP
	id AA19439; Mon, 3 Oct 94 19:50:02 EDT
Received: from freeside.fc.net (freeside.fc.net [198.6.198.2]) by villa.fc.net (8.6.8.1/8.6.6) with ESMTP id CAA00990 for <bugtraq-outgoing@villa.fc.net>; Mon, 3 Oct 1994 02:44:17 -0500
Received: (from majordom@localhost) by freeside.fc.net (8.6.8.1/8.6.6) id CAA04421 for bugtraq-outgoing@villa.fc.net; Mon, 3 Oct 1994 02:44:47 -0500
Received: from crimelab.crimelab.com (crimelab.crimelab.com [198.64.127.1]) by freeside.fc.net (8.6.8.1/8.6.6) with ESMTP id CAA04399 for <bugtraq@fc.net>; Mon, 3 Oct 1994 02:43:51 -0500
Received: from relay2.UU.NET (relay2.UU.NET [192.48.96.7]) by crimelab.crimelab.com (8.6.9/8.6.4) with ESMTP id CAA11269 for <bugtraq@crimelab.com>; Mon, 3 Oct 1994 02:38:53 -0500
Received: from nwnexus.wa.com by relay2.UU.NET with SMTP 
	id QQxjzi18268; Mon, 3 Oct 1994 03:39:44 -0400
Received: from ole.cdac.com by nwnexus.wa.com with SMTP id AA25501
  (5.65c/IDA-1.4.4 for <uunet!crimelab.com!bugtraq@nwnexus.wa.com>); Mon, 3 Oct 1994 00:39:39 -0700
Received: from rwing.UUCP by ole.cdac.com with UUCP id AA09101
  (5.67b/IDA-1.5 for nwnexus!uunet!crimelab.com!bugtraq); Mon, 3 Oct 1994 00:37:41 -0700
Received: by rwing.UUCP (5.65/smail2.5/04-05-92)
	id AA04490; Mon, 3 Oct 94 00:29:06 -0700
From: rwing!pat@ole.cdac.com (Pat Myrto)
Message-Id: <9410030729.AA04490@rwing.UUCP>
Subject: SUMMARY Security Info (root broken)
To: bugtraq@crimelab.com
Date: Mon, 3 Oct 94 0:29:02 PDT
X-Mailer: ELM [version 2.3 PL11]
Sender: bugtraq-owner@crimelab.com
Precedence: bulk

Bugtraq gurus:

This is the summary regarding my query about how people can so easily
break root or other accounts using /bin/mail on SunOS 4.1.3_U1.  Individual
copies of responses is not possible, due to the volume.  Several included
the 8lgm advisories I had missed, and the other principles summarized
below were extremely helpful.

Turns out this is not all that new a problem - like it has whiskers.
It exists on all the SunOS 4.1x versions, and most likely earlier
versions as well, and might exist in one form or another on any
site that uses the /bin/mail delivery agent running as root, and
a world-writeable mail spool - even with the sticky bit set (as it
should be).

This particular problem does not occur on SysV type mail systems, where
the mail spool is owned by root.mail, and mode 775.  The mail agent
runs SGID mail instead of SUID root, because root is not required to
do a chown (one can 'give away' a file, but not chown a file not
owned by the user - root privs are required for that).

Preventative measures include ensuring that all accounts have a mailbox,
even an empty one.  Set the global /usr/lib/Mailrc file to include
the line 'set keep', and build all other mail user agents to leave
an empty mailbox, instead of deleting it when one deletes all mail.

When adding a user, create a zero-length mailbox for that user.
If you have no need for a root .rhosts file, link it to /dev/null
or do a mkdir /.rhosts, with no write privs.  Also, eliminate all
UID 0 accounts (sundiag, etc) other than root, since the same attack
can be done making an .rhosts file in their home subdirs.  It matters
not whether these accounts have a valid shell or not.  Careful use
of the r commands may help, too (disabling the r commands looks like
a fix, but this may well create more problems than they solve - it
will increase the frequency of password entry, and susceptibility
to sniffer attacks).

And most important, REPLACE OR FIX BINMAIL.  The current patch offered
by Sun apparantly does NOT fix the problem, only alters it.  Using
something built from mail.local.c from the NetBSD distribution is a good
alternative.  Just name the executalbe mail and install it in place of
the original, and you don't even need to muck with sendmail config files.
Another party suggested using procmail as the delivery agent, I haven't
investigated this.

One of the respondents (Chuck Cranor - chuck@maria.wustl.edu) sent such
a replacement he has used, it is included in this summary.  BE WARY OF
ALL PRIVILEGED PROGRAMS THAT CREATE TEMPORARY FILES IN /tmp.  Too often
these programs also have a race condition, and one can predict the name
of the temp file the program will use, and thus exploit this.  This is
not helped by having all the mailboxes in place, since this works in
tmp instead of the mail spool.  If one has source, at lease make sure
that the temp files are created and opened via the mkstemp() call, not
mktemp() followed by an open.  Check via lstat and fstat to ensure the
file one opens is the one that one THINKS one is opening.  The program
appended adds another wrinkle - using chroot() and fchroot() to limit
the scope of where links can point to if a link is somehow slipped under
the the program via winning a race.  As long as checking the file to be
opened and the open are not atomic, potential for this problem exists
with privileged programs.

Thanks so very much for such a tremendous and educational response!!!
Not only did I get several options and tests for fixing this problem,
but also insight into where to look for other similar type problems.
This is the kind of information that will at least keep the legit admins
neck-and-neck with the crackers (who have nothing better to do all day
but devise more attacks, apparantly).

 From Chuck Cranor chuck@maria.wustl.edu / cranor@udel.edu:
---------------------- reworked mail.local.c --------------------
/*-
 * Copyright (c) 1990 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.
 *
 * Modified by: Chuck Cranor chuck@maria.wustl.edu / cranor@udel.edu 
 *
 */

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

#ifndef lint
/*static char sccsid[] = "from: @(#)mail.local.c	5.6 (Berkeley) 6/19/91";*/
static char rcsid[] = "$Id: mail.local.c,v 1.5 1994/02/10 05:33:21 briggs Exp $";
#endif /* not lint */

#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <syslog.h>
#include <fcntl.h>
#include <netdb.h>
#include <pwd.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef sunos

#include "pathnames.h"

#else

/* stuff that is missing on sunos */
#define __P(x) ()
#define _PATH_LOCTMP    "/tmp/local.XXXXXX"
#define _PATH_MAILDIR	"/var/spool/mail"
#include <utmp.h>
struct utmp ut; /* for sizeof(ut.ut_name) */
#define O_EXLOCK 0
#include <sys/file.h>
extern char *sys_errlist[];
#define strerror(x) sys_errlist[(x)]

#endif /* sunos */

#define	FATAL		1
#define	NOTFATAL	0

int	deliver __P((int, char *, int));
void	err __P((int, const char *, ...));
void	notifybiff __P((char *));
int	store __P((char *));
void	usage __P((void));

main(argc, argv)
	int argc;
	char **argv;
{
	extern int optind;
	extern char *optarg;
	struct passwd *pw;
	int ch, fd, eval, lockfile=0;
	uid_t uid;
	char *from;

#ifdef sunos
	openlog("mail.local", 0, LOG_MAIL);
	lockfile = 1; /* always lockfile it */
#else
	openlog("mail.local", LOG_PERROR, LOG_MAIL);
#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)
			    err(FATAL, "multiple -f options");
			from = optarg;
			break;
		case 'l':
			lockfile++;
			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 : "???";

	fd = store(from);
	for (eval = 0; *argv; ++argv) {
		if (strlen(*argv) > sizeof(ut.ut_name))
			*argv[sizeof(ut.ut_name)] = 0; 
					/* don't overflow sprintfs */
		eval |= deliver(fd, *argv, lockfile);
	}
	exit(eval);
}

store(from)
	char *from;
{
	FILE *fp;
	time_t tval;
	int fd, eline;
	char *tn, line[2048];

	tn = strdup(_PATH_LOCTMP);
	if ((fd = mkstemp(tn)) == -1 || !(fp = fdopen(fd, "w+")))
		err(FATAL, "unable to open temporary file");
	(void)unlink(tn);
	free(tn);

	(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' && !bcmp(line, "From ", 5))
				(void)putc('>', fp);
			eline = 0;
		}
		(void)fprintf(fp, "%s", line);
		if (ferror(fp))
			break;
	}

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

	(void)fflush(fp);
	if (ferror(fp))
		err(FATAL, "temporary file write error");
	return(fd);
}

/*
 *
 * function: safelock
 * author: Chuck Cranor <chuck@maria.wustl.edu>
 *
 * this becomes complex, due to our dear friend, the NFS mounted mail spool.
 * the netbsd code didn't do this properly, as far as I could tell.
 *
 * program notes: 
 *	[1] you can't trust exclusive creating opens over NFS, the protocol
 *          just doesn't support it.   so to do a lock you have to create
 *          a tmp file and then try and hard link it to your lock file.
 *      [2] to detect a stale lock file you have to see how old it is, but
 *          you can't use time(0) because that is the time on the local system
 *          and the file gets the times of the NFS server.  when is a lock
 *          file stale?  people seem to like 120 or 300 seconds.  
 *	[3] oh, and of course most NFS mounted file systems translate 
 *          "root" requests to "nobody", so you have to drop privs to do 
 *          any file ops.
 *
 *        this code was written from scratch, but based on the 
 *        "lk_lock.c" file from MMDF, and various stuff i've read 
 *        on the net about file locking and NFS.
 *        
 * args: lpath = full path name of lock file (/var/spool/mail/chuck.lock)
 *       namelock = file name of lock file (chuck.lock)
 *       uid = who should own the lock file
 *       ( could derive namelock from lpath, but i'm too lazy )
 */

safelock(lpath, namelock, uid) 

char *lpath, *namelock;
int uid;

{
  int tries = 0, oldlck = 0, tmpfd, ruid;
  struct stat old_stat, our_tmp;
  char tmp[32];
  char *tpath;
  srandom(getpid()+time(0));

  /*
   * 1. create a tmp file with a psuedo random file name.  we use
   *    safeopen to "do it".  we also make tpath which is a buffer
   *    to store the full pathname of the tmp file.
   */

  sprintf(tmp,"slock%d.%d", getpid(), random());

  tpath = malloc(sizeof(_PATH_MAILDIR) + 1 + strlen(tmp) + 1);
  if (tpath == NULL) return(-1);
  sprintf(tpath,"%s/%s", _PATH_MAILDIR, tmp);

  tmpfd = safeopen(_PATH_MAILDIR, tmp, uid, O_CREAT|O_WRONLY|O_EXCL, 
		S_IRUSR|S_IWUSR, 5);

  /*
   * 1b. check for failure
   */

  if (tmpfd < 0) {
    close(tmpfd);
    unlink(tpath);
    free(tpath);
    return(-1);
  }

  /*
   * 2. start looping trying to lock it
   */

  while (tries < 10) {

    /*
     * 3. link tmp file to lock file.  if it goes, we win and we clean
     *    up and return the fd of the lock file.
     */

    if (link(tpath, lpath) == 0) {
      unlink(tpath); /* got it! */
      free(tpath);
      return(tmpfd);
    }

    /*
     * 4. the lock failed.  check for a stale lock file, being mindful
     *    of NFS and the fact the time is set from the NFS server.  we
     *    do a write on the tmp file to update its time to the server's
     *    idea of "now."
     */

    oldlck = lstat(lpath, &old_stat);

    if (write(tmpfd, "\0", 1) != 1 || fstat(tmpfd, &our_tmp) < 0)
      break; /* something bogus is going on */

    if (oldlck != -1 && old_stat.st_ctime + 300 < our_tmp.st_ctime) {
      ruid = getuid(); /* drop privs for NFS */
      setreuid(0, uid);
      unlink(lpath); /* break the stale lock */
      setuid(0);
      setreuid(ruid, 0);
    }

    /*
     * 5. try again
     */

    tries++;
    sleep(1+(random() % 10));
  }

  /*
   * 6. give up, failure.
   */

  errno = EEXIST;
  unlink(tpath);
  free(tpath);
  return(-1);
}


deliver(fd, name, lockfile)
	int fd;
	char *name;
	int lockfile;
{
	struct stat sb;
	struct passwd *pw;
	int created, mbfd, nr, nw, off, rval=0, lfd=-1;
	char biffmsg[100], buf[8*1024], path[MAXPATHLEN], lpath[MAXPATHLEN];
	char namelock[sizeof(ut.ut_name)+1+5];
	off_t curoff, lseek();

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

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

	if(lockfile) {
		(void)sprintf(lpath, "%s/%s.lock", _PATH_MAILDIR, name);

		sprintf(namelock,"%s.lock", name);
		if((lfd = safelock(lpath, namelock, pw->pw_uid)) < 0) {
			err(NOTFATAL, "%s: %s", lpath, strerror(errno));
			return(1);
		}
	}

	if (!(created = lstat(path, &sb)) &&
	    (sb.st_nlink != 1 || S_ISLNK(sb.st_mode))) {
		err(NOTFATAL, "%s: linked file", path);
		return(1);
	} /* leave it in, but don't trust it */

	if((mbfd = safeopen(_PATH_MAILDIR, name, pw->pw_uid, 
	    O_APPEND|O_WRONLY|O_EXLOCK|O_CREAT, S_IRUSR|S_IWUSR, 5)) < 0) {
		err(NOTFATAL, "%s: %s", path, strerror(errno));
		return(1);
	}
#ifdef sunos
	flock(mbfd, LOCK_EX); /* XXX is this needed?  doesn't work with NFS */
#endif

	curoff = lseek(mbfd, 0L, SEEK_END);
	(void)sprintf(biffmsg, "%s@%ld\n", name, curoff);/*XXX*/
	if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
		err(FATAL, "temporary file: %s", strerror(errno));
		rval = 1;
		goto bad;
	}

	while ((nr = read(fd, buf, sizeof(buf))) > 0)
		for (off = 0; off < nr;  off += nw)
			if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
				err(NOTFATAL, "%s: %s", path, strerror(errno));
				goto trunc;
			}
	if (nr < 0) {
		err(FATAL, "temporary file: %s", strerror(errno));
trunc:		(void)ftruncate(mbfd, curoff);
		rval = 1;
	}

	/*
	 * Set the owner and group.  Historically, binmail repeated this at
	 * each mail delivery.  We no longer do this, assuming that if the
	 * ownership or permissions were changed there was a reason for doing
	 * so.
	 */
bad:
	if(lockfile) {
		if(lfd >= 0) {
			unlink(lpath);
			close(lfd);
		}
	}
	if (created) 
		(void)fchown(mbfd, pw->pw_uid, pw->pw_gid);

	(void)fsync(mbfd);		/* Don't wait for update. */
	(void)close(mbfd);		/* Implicit unlock. */

	if (!rval)
		notifybiff(biffmsg);
	return(rval);
}

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"))) {
			err(NOTFATAL, "localhost: %s", strerror(errno));
			return;
		}
		addr.sin_family = hp->h_addrtype;
		bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
		addr.sin_port = sp->s_port;
	}
	if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		err(NOTFATAL, "socket: %s", strerror(errno));
		return;
	}
	len = strlen(msg) + 1;
	if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr))
	    != len)
		err(NOTFATAL, "sendto biff: %s", strerror(errno));
}

void
usage()
{
	err(FATAL, "usage: mail.local [-f from] user ...");
}

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

void
#if __STDC__
err(int isfatal, const char *fmt, ...)
#else
err(isfatal, fmt, va_alist)
	int isfatal;
	char *fmt;
	va_dcl
#endif
{
	va_list ap;
#if __STDC__
	va_start(ap, fmt);
#else
	va_start(ap);
#endif
	vsyslog(LOG_ERR, fmt, ap);
#ifdef sunos
	vfprintf(stderr, fmt, ap);
	fprintf(stderr,"\n");
#endif
	va_end(ap);
	if (isfatal)
		exit(1);
}


/*
 * safeopen: a somewhat paranoid safeopen call
 * author: Chuck Cranor <chuck@maria.wustl.edu>
 * date: 30-Apr-94
 * note: based on comments from 8lgm, comp.securty.unix, and my own ponderings.
 *       consider this function public domain code
 */

/*
 * safeopen:
 *   dir = directory to open in
 *   file = file name
 *   uid = who should own the file (should equal the uid we create files under)
 *   flags = flags to open(2)
 *   mode = mode to open(2)
 *   tries = number of times to try to safeopen the file (so if someone
 *           is reading the mailbox and changes it in the middle we don't
 *           just fail... )
 */

int safeopen(dir, file, uid, flags, mode, tries)

char *dir, *file;
int uid, flags, mode, tries;

{
  int retval = -1;
  int pr = 1;

  while (retval == -1) {
    retval = safeopen1(dir, file, uid, flags, mode, pr);
    tries--;
    pr = 0;
    if (retval != - 1 || tries < 0) break;
    sleep(1);
  }
  return(retval);
}

/*
 * safeopen1: try 1 time to safeopen a file, "pr" says if we should print 
 *   error messages to stderr
 */

int safeopen1(dir, file, uid, flags, mode, pr)

char *dir, *file;
int uid, flags, mode, pr;

{
  struct stat st1,  st2, st3;
  int retval = -1, new = 0, fd = -1, ruid;
  extern int errno;
  char *slash_file;
  int stat_mode = mode | S_IFREG;

  /*
   * 1a. chroot to "dir" to avoid creating random zero length files
   *    due to symb. links, get new file name
   */

  int root = open("/", O_RDONLY);
  slash_file = malloc(strlen(file) + 2);
  if (root < 0 || chroot(dir) < 0 || slash_file == NULL) {
    if (root >= 0) close(root);
    if (pr) 
      fprintf(stderr,"safeopen: init failed (%s)!\n", strerror(errno));
    return(-1);
  }
  sprintf(slash_file,"/%s", file);

  /*
   * 1b. drop privs
   */

  ruid = getuid();
  setreuid(0, uid);

  /*
   * 2. lstat the file.  new is true if the file wasn't there.
   *    abort on strange errors.
   */

  new = (lstat(slash_file, &st1) < 0);
  if (new && errno != ENOENT) {
    if (pr)
      fprintf(stderr,"safeopen: can't stat %s/%s - stat failed (%s)\n", dir, 
        file, strerror(errno));
    goto done;
  }

  /*
   * 3. here is the old safefile check for sanity, but we don't trust it
   */

  if (!new) {
    if (((st1.st_mode & S_IFMT) != S_IFREG) || st1.st_nlink != 1) {
        if (pr)
          fprintf(stderr,"safeopen: %s/%s: non file or wrong link count", dir,
             file);
      goto done;
    }
  }

  /*
   * 4. open the file
   */

  fd = open(slash_file, flags, mode);
  if (fd < 0) {
    if (pr)
      fprintf(stderr,"safeopen: can't open %s/%s - open failed (%s)\n", dir, 
        file, strerror(errno));
    goto done;
  }

  /*
   * 5. do a fstat on our file handle, and then lstat again for the 
   *    heck of it.
   */

  if (fstat(fd, &st2) < 0 || lstat(slash_file, &st3) < 0) goto done;

  if (new) {

    /*
     * 6a. for new files, check that the two previous stats agree.
     *     also since we created the file, we know exactly what its
     *     mode, link count, and owner should be.  if the don't match
     *     then someone is playing with us, so we silently abort.
     */

    if (st2.st_dev != st3.st_dev) goto done;
    if (st2.st_ino != st3.st_ino) goto done;
    
    if (st2.st_mode != stat_mode || st2.st_mode != st3.st_mode) goto done;
    if (st2.st_nlink != 1 || st3.st_nlink != 1) goto done;
    if (st2.st_uid != uid || st2.st_uid != st3.st_uid) goto done;
    
    retval = fd;   /* looks ok ! */
    goto done;
    
  }

  /*
   * 6b. file was there (so first lstat is in st1), do the same checks
   *     as 6a, but also let's check st1 too!
   */
   
  if (st1.st_dev != st2.st_dev || st2.st_dev != st3.st_dev) goto done;
  if (st1.st_ino != st2.st_ino || st2.st_ino != st3.st_ino) goto done;
  if (st1.st_mode != st2.st_mode || st2.st_mode != st3.st_mode) goto done;
  if (st2.st_nlink != 1 || st2.st_nlink != st3.st_nlink) goto done;
  if (st1.st_uid != st2.st_uid || st2.st_uid != st3.st_uid) goto done;

  retval = fd;  /* looks ok ! */

done:
  setuid(0);          /* restore old privs */
  setreuid(ruid, 0);  
  fchroot(root);
  close(root);
  if (retval < 0 && fd != -1) close (fd);
  free(slash_file);
  return(retval);
}
----------------------- end reworked mail.local.c ----------------------

The following might be a candidate for a periodically run cron job.
I say candidate, because I haven't tried it in this manner yet.

------- begin makemailboxes.c (shamelessly borrowed from 8lgm advisory) ---
/*
 * makemailboxes.c
 *
 * Written 1994 by [8LGM]
 *
 * This program is part of a workaround for the SunOS 4.1.x /bin/mail
 * bug described in the 8LGM Advisory.  This program should be executed
 * as root, and will create a mailbox for each user that doesnt have one.
 * In order for this workaround to be effective, /usr/ucb/Mail also needs
 * to be wrapped with wrapper.c.
 */

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <sys/file.h>
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>

#define MAIL_SPOOL_DIR "/var/spool/mail"

main(argc, argv)
int argc;
char *argv[];
{
        int    fd;
        char   path[MAXPATHLEN + 5];
        struct passwd *pw;

        umask(0);
        setpwent();
        while (pw = getpwent()) {
                sprintf(path, "%s/%s", MAIL_SPOOL_DIR, pw->pw_name);
                if (access(path, F_OK)) {
                        if ((fd = open(path,O_CREAT|O_EXCL|O_WRONLY, 0600)) < 0)
                                perror("open");
                        else {
                                if (fchown(fd, pw->pw_uid, pw->pw_gid))
                                        perror("fchown");
                                close(fd);
                                printf("Created %s\n", path);
                        }
                }
        }
        endpwent();
        exit(0);
}
----------------- end makemailboxes.c -----------------------------------

Following is a list of all the people who responded to my query.  Thanks
all of you!

"Alexander L. Haiut" <ole!CS.bgu.ac.il!alx>
"David A. Wagner" <ole!phoenix.Princeton.EDU!dawagner>
"Perry E. Metzger" <ole!imsi.com!perry>
"That Whispering Wolf..." <ole!lupine.org!elfchief>
"Todd C. Welch" <ole!nsipo.nasa.gov!welch>
"[8LGM] Security Team" <8lgm@bagpuss.demon.co.uk>
Adam Shostack <ole!bwh.harvard.edu!adam>
Christopher Davis <ole!loiosh.kei.com!ckd>
Christopher Klaus <ole!shadow.net!cklaus>
Chuck Cranor <ole!maria.wustl.edu!chuck>
Dave Mack <ole!net.bio.net!dmack>
John Ladwig <ole!Soils.Umn.EDU!jladwig>
John Nemeth <ole!cue.bc.ca!jnemeth>
Karl Strickland <karl@bagpuss.demon.co.uk>
Karl Strickland <ole!bagpuss.demon.co.uk!karl>
Michael Platoff <ole!scr.siemens.com!michael.platoff>
Neil Woods <ole!legless.demon.co.uk!neil>
Paul Walmsley <ole!everest.cclabs.missouri.edu!c617666>
Pauline van Winsen - Uniq Professional Services <ole!uniq.com.au!pauline>
Peter Phillips <ole!cs.ubc.ca!pphillip>
Pug <ole!arlut.utexas.edu!pug>
Rob Jenson <ole!disaster.gsfc.nasa.gov!rbj>
SunSolve User <sunsolve@sunsolve1.sun.com>
chuck@dworkin.wustl.edu (Chuck Cranor)
der Mouse <ole!Collatz.McRCIM.McGill.EDU!mouse>
ole!corsof.com!DanaNowell (Dana Nowell)
ole!dt.wdc.com!kumeda (Andy Kumeda (Kumeda)
ole!ebay.sun.com!Brad.Powell (Brad Powell)
ole!london.micrognosis.com!nreadwin (Neil Readwin)
ole!msmary.edu!covingto (Michael Covington)
ole!pine.cse.nau.edu!unkadath!shamus (James W. Abendschan)
ole!plan9.research.att.com!ches
ole!sol.uvic.ca!klassen (Melvin Klassen)
ole!sqwest.wimsey.bc.ca!mch (Mark C. Henderson)
ole!std.sbi.com!bet (Bennett Todd)
pluvius <ole!dragon.achilles.net!pluvius>

<whew>!

-- 
pat@rwing  [If all fails, try:  rwing!pat@eskimo.com]  Pat Myrto - Seattle WA
"No one has the right to destroy another person's belief by demanding
empirical evidence."  --   Ann Landers, nationally syndicated advice columnist
and Director at Handgun Control Inc.

home help back first fref pref prev next nref lref last post