[net.unix-wizards] Mail Security and Locking Problem parse date string

lepreau@utah-cs.UUCP (06/02/83)

I recently discovered a serious mail locking problem which affects every
4.1 system which has a non-777 /usr/spool/mail, and probably some other
systems as well (v7 and 2.8 likely, maybe USG, but haven't checked).
The lock files created by the setuid deliverer (binmail) and the
non-setuid user agents (Mail, emacs rmail, etc) are created in
/usr/spool/mail!  So if it's not 777 the user Mail programs merrily go
along after their mktemps and links fail, certainly clobbering mail
files sometimes.

The locking scheme UCB uses is general enough that it is trivially
changed to do locking on /tmp.  Of course all the programs must be
changed "at once," but that took me all of about two minutes a program,
as binmail and Mail use almost identical code.  MH uses a less general
scheme but that could easily be changed to use this scheme. (WARNING to
emacs users: as distributed, Gosling's emacs collectmail does only
kernel-level locking via CMU's flock ioctl, and if that's not present
then it doesn't even pretend to lock.  Installation is easily made in it
also.)  4.2's locking primitives should be used except they are
non-portable.  The Berkeley people may or may not get around to fixing
this before the release (or ever), so watch for it later also.

It appears to me that the check for multiple links in UCB's current
binmail, along with the kernel's reseting the setuid bit on chown()
plugs the obvious security holes with a 777 mail dir.  But we still
don't like it for a variety of obvious reasons, including some naive
user doing rm -f * there.  I remember back over a year and a half ago
the discussion on wizards about security, and many many people indicated
how easy it was to make the mail mods to protect the spool dir, but no
one mentioned the locking protocol.  I'm sure this problem is
widespread.  Fix it now!

Diff of mail.c follows; changes in Mail/lock.c are almost identical.

-Jay Lepreau   lepreau@utah-cs.ARPA, harpo!utah-cs!lepreau


*** /tmp/,RCSt1004008	Fri May 13 17:13:18 1983
--- mail.c	Thu Apr  7 09:43:12 1983
***************
*** 11,13
  static char RCSid[] =
! "$Header: RCS/mail.c,v 1.4 83/04/07 09:01:38 lepreau Exp $";
  /* Version 4.13 less 4.9 and 4.11 (4.1c changes) */

--- 11,13 -----
  static char RCSid[] =
! "$Header: RCS/mail.c,v 1.6 83/04/07 09:42:55 lepreau Exp $";
  /* Version 4.13 less 4.9 and 4.11 (4.1c changes) */
***************
*** 39,40
  char	*index();
  char	lettmp[] = "/tmp/maXXXXX";

--- 39,41 -----
  char	*index();
+ char	*rindex();
  char	lettmp[] = "/tmp/maXXXXX";
***************
*** 680,681
   * Otherwise, we wait for 5 seconds and try again.
   */

--- 681,683 -----
   * Otherwise, we wait for 5 seconds and try again.
+  * Lock file is "/tmp/username.lock".
   */
***************
*** 683,685
  char	*maillock	= ".lock";		/* Lock suffix for mailname */
! char	*lockname	= "/usr/spool/mail/tmXXXXXX";
  char	locktmp[30];				/* Usable lock temporary */

--- 685,688 -----
  char	*maillock	= ".lock";		/* Lock suffix for mailname */
! char	*lockname	= "/tmp/tmXXXXXX";	/* target for link */
! char	*lockdir	= "/tmp/";		/* where it all happens */
  char	locktmp[30];				/* Usable lock temporary */
***************
*** 695,696
  	int statfailed;


--- 698,700 -----
  	int statfailed;
+ 	register char *p;

***************
*** 698,700
  		return(0);
! 	strcpy(curlock, file);
  	strcat(curlock, maillock);

--- 702,709 -----
  		return(0);
! 	if ((p = rindex(file, '/')) == NULL)	/* point to last component */
! 		p = file;
! 	else
! 		p++;
! 	strcpy(curlock, lockdir);
! 	strcat(curlock, p);
  	strcat(curlock, maillock);