Subject: Pine being setgid mail (was: .lock mailbox locking)

From: Jos Vos <[email-masked]>
Date: Wed, 20 Oct 93 10:46:06 MET

Some good and some bad news.

The good news is that making "pine" setgid mail (on System V systems)
makes .lock mailbox locking work fine.
Although it ignores failing .lock mailbox locking when the access is
prohibited (i.e., when pine is not setgid mail and the mail directory
is 775, is it should be), it honours existing .lock files and it creates
its own .lock file if necessary.

Now the bad news.

When pine is setgid mail, I can read evertbody's mailbox.
I did this by creating a symlink in my $HOME/mail directory
to another user's mailbox.

This is a *serious* security problem: System V mail locking is based on
.lock files, basically, and this *should* work properly.

-- 
--    Jos Vos <[email-masked]>   (UUCP: ...!{uunet,mcsun,sun4nl}!nlbull!jos)
--    Bull Netherlands, Professional Services, Amsterdam, The Netherlands

---

From: Mark Crispin <[email-masked]>
Date: Wed, 20 Oct 1993 13:47:51 -0700 (PDT)

Pine is not intended to run with any setuid and setgid privileges.  Nor
is imapd.

     It is questionable that an improvment to system security is made by
creating a requirement that all mail-reading programs run with privileges.  It
is even more questionable that security is enhanced by granting privileges to
software other than that provided by your vendor.

     The infamous bug with the ``move-mail'' program, used by the cracker in
``The Cuukoo's Egg'', suggests the great danger of requiring privileges in
order to enable fundamental user tasks such as mail reading.  It should be
noted that move-mail itself was designed to be a ``safe'' privileged program
to do a particular task that required privileges so the main program did not
need any privileges.

     Pine has always supported .lock files.  This are one of the fundamental
aspects of locking in the mbox format.  The problem is that an unprivileged
program is not allowed to create .lock files on your system, because of the
bad protection you have placed on the /usr/spool/mail directory.

     A separate message outlined an alternative strategy for dealing with the
problem of a mischeivous user being able to create a mail file for someone
else.  Although this strategy is more complex, I urge you to give it serious
consideration.  Please also consider the great danger of having to give many
mail programs privileged access.

     I will suggest to my co-workers about the possibility of making Pine and
imapd safe to run with setgid privileges.  It would be a great deal of work to
make these programs privilege-safe, and the problem can be solved by an
alternative configuration on your system.  So I can't make any promises.

     If you have any further questions, please do not hesitate to ask.

---

From: "A. Hilborne" <[email-masked]>
Date: Thu, 21 Oct 1993 09:41:20 +0100 (BST)

I have read your three messages on this subject.  I must say I was initially
surprised that pine doesn't run setgid.

I must be one among many who can't really contemplate using your "alternative
strategy."   Mail is only one of many services here and we can't put that much
effort into something which only improves, rather than fixes matters.  Nor do we
want a situation in which we have to continually create ~ 5,000 (mainly empty)
mailboxes in our spool area! 

You suggest disabling chown.  To do this effectively would mean a kernel
change.

You suggest we should endeavour to create a non-adversarial relationship with
our users:  I wholeheartedly agree here, but university students _will_
sometimes try to break security, whatever we do.

We are fortunate:  both our main system types (HP-UX and SunOS) support the
alternative meaning of the sticky bit on directories, so we are partially
protected from abuses of a rwxrwxrwx mail spool.  We still aren't fully
protected against users who create "false" mailboxes on behalf of others.

What to do?  Given an adequate modern Unix which will allow a setuid-program to
switch back and forth between identities there is no need for such a program to
"check itself to make sure that system integrity is not being compromised,"
except inside the "security box" in the program.  Everywhere else the program
runs with normal user privileges.  Some additional care also needs to be taken
with system resources (such as file descriptors) which are acquired inside the
security box but used outside of it.

Clearly such a restructuring of Pine would be a lot of work, but the result
needn't be much more dangerous running setgid than Pine is now.

--
Andrew M. Hilborne                        [email-masked]
Computing Service                    Tel: +44 91 222 8226 (direct)
University of Newcastle upon Tyne, UK.    +44 91 222 8039 (Comp Service office)

---

From: Mark Crispin <[email-masked]>
Date: Thu, 21 Oct 1993 03:00:49 -0700 (PDT)

The fact is, making your /usr/spool/mail directory protected 775 does *not*
``fix matters''.  It breaks matters in two related ways:
 1) Unprivileged programs can not be mail readers.  So, if someone has a neat
    idea for the Ultimate Mail Reader, he cannot write it on your system,
    because your system's policy prevents it.  If he sees a new nifty mail
    program on the net, he can't just FTP it to his directory and run it,
    because only programs that the system manager approves can be mailers.
 2) All mail readers must be privileged, and the slightest oversight in ANY
    single mail reader compromises your entire system.  How many more horror
    stories do there have to be about the setuid program that allowed you to
    spawn a root shell with !, before people realize how serious a problem
    this is?

I hardly call this an ``improvement'', much less a ``fix''.  It creates
adversarial relationships and provides multiple stress points that can be
tested for weaknesses.

I have discussed the question of making Pine be set[gu]id safe with my co-
workers, and I'll bring it up with our boss.  No decision has been made.  If
done, it is going to be a tremendous amount of work, now and in the future.

We have a very long ``to-do'' list of feature enhancements and bugs to be
fixed.  Should we divert our limited resources for several months (or longer)
towards an effort that adds no user function and is unnecessary with better
site management?

Would offering a /bin/mail substitute (you would edit your sendmail.cf to run
it instead of /bin/mail) that protects against mail being delivered to false
mailboxes be a satisfactory alternate?  We can offer this in a finite amount
of time.  This would fix the problem without requiring that mail readers run
with privileges.

Regards,

-- Mark --

---

From: Hannu Martikka <[email-masked]>
Date: Thu, 21 Oct 1993 15:49:13 +0200

Could it be possible to use some small external program from pine to
handle locking?
--
Regards from Goodi
______________________________________________________________________________
Internet: [email-masked]  / \  
Bitnet  : GOODGULF@FINFILES     // \\             \-\-\-\-\-\-\	oh5lhh
Hannu Martikka,Skinnarilankatu /// \\\ 	            |		on 70cm	
28 F17, 53850 Lappeenranta,SF /// | \\\_____________|________________________
Home Tel. +358-(9)53-251446	  | :) Lappeenranta University Of Technology |
------------------------------------------------------------------------------

---

From: Steinar Haug <[email-masked]>
Date: Thu, 21 Oct 1993 15:58:26 +0100 (MET)

> You suggest disabling chown.  To do this effectively would mean a kernel

You write later that your main systems are HP-UX and SunOS. You certainly
don't need a kernel change for these systems!

- For SunOS 4.1.x, chown to another user is *not* allowed, ie it follows
the BSD standard, not the System V standard.

- For HP-UX, chown to another user is by default allowed. It can easily
be turned off by creating /etc/privgroup which contains *one* line:

	-n CHOWN

If you want programs which are setgid to mail (eg. /bin/rmail) to be able
to do chown, you need:

	-n CHOWN
	mail CHOWN

In both cases, extremely easy.

Steinar Haug, system/networks administrator
SINTEF RUNIT, University of Trondheim, NORWAY
Email: [email-masked], [email-masked]

---

From: Jos Vos <[email-masked]>
Date: Thu, 21 Oct 93 17:14:45 MET

> imapd safe to run with setgid privileges.  It would be a great deal of work t

I've made a quick hack to temporarily solve the problem:

-  Pine (and other programs opening folders) run setgid mail,
   being compiled with SETGID_HACK set.

-  In main() the first thing to do is to save the effective gid,
   and do a setgid(getgid()) (disable the setgid stuff).

-  In the lock and unlock functions I temporarily restore the
   saved effective gid when performing the actual locking/unlocking
   actions.

-  This means that, except for the small pieces of code doing the
   (un)locking, pine runs with the real gid, and opening another
   person's mailbox is impossible.

-  All the stuff still works as before when not running setgid
   mail.  Then the effective gid is the same as the real gid, so all
   setgid() actions are in fact a no-op.

-  I've tested it here with pine, and it seems to work fine.
   I didn't test it with imapd, because I don't use it (yet).

-  I consider it an unelegant hack, but it works.
   I invite everybody to make comments (and test everything
   thoroughly), so that we can suggest it as a standard solution
   to the Pine development team.

------CUT HERE------
*** pine/pine.c-	Wed Oct 20 15:28:04 1993
--- pine/pine.c	Wed Oct 20 15:16:09 1993
***************
*** 62,68 ****
--- 62,72 ----
  struct pine *ps_global;               /* sort of THE global variable */
  int          timeout = NEW_MAIL_TIME; /* referenced in weemacs */
  
+ #ifdef SETGID_HACK
+ gid_t        egid;
+ #endif
  
+ 
  /*----------------------------------------------------------------------
    General use big buffer. It is used in the following places:
      compose_mail:    while parsing header of postponed message
***************
*** 214,219 ****
--- 218,230 ----
      char          int_mail[MAXPATH+1];
  #ifdef DYN
      char stdiobuf[64];
+ #endif
+ 
+ #ifdef SETGID_HACK
+     /* Save effective group ID (probably the group ID of "mail") */
+     egid = getegid();
+     /* Replace the effective group ID with the real group ID */
+     (void) setgid(getgid());
  #endif
  
      /*----------------------------------------------------------------------
*** imap/ANSI/c-client/bezerk.c-	Thu Oct 21 16:19:57 1993
--- imap/ANSI/c-client/bezerk.c	Thu Oct 21 16:21:24 1993
***************
*** 60,65 ****
--- 60,69 ----
  #include "rfc822.h"
  #include "misc.h"
  #include "dummy.h"
+ 
+ #ifdef SETGID_HACK
+ extern gid_t egid;
+ #endif
  
  /* Berkeley mail routines */
  
***************
*** 1116,1121 ****
--- 1120,1130 ----
    char tmp[MAILTMPLEN];
    struct timeval tp;
    struct stat sb;
+ 
+ #ifdef SETGID_HACK
+   /* Restore effective group ID (probably group "mail") for locking */
+   (void) setgid(egid);
+ #endif
  				/* build lock filename */
    strcat (bezerk_file (lock,file),".lock");
    do {				/* until OK or out of tries */
***************
*** 1187,1192 ****
--- 1196,1206 ----
        sleep (1);		/* wait 1 second before next try */
      }
    } while (i-- && ld < 0 && *lock);
+ 
+ #ifdef SETGID_HACK
+   /* Disable effective group ID (locking is done now) */
+   (void) setgid(getgid());
+ #endif
  				/* open file */
    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
    else {			/* open failed */
***************
*** 1220,1227 ****
--- 1234,1250 ----
    }
    flock (fd,LOCK_UN);		/* release flock'ers */
    close (fd);			/* close the file */
+ 
+ #ifdef SETGID_HACK
+   /* Restore effective group ID (probably group "mail") for unlocking */
+   (void) setgid(egid);
+ #endif
  				/* flush the lock file if any */
    if (lock && *lock) unlink (lock);
+ #ifdef SETGID_HACK
+   /* Disable effective group ID (unlocking is done now) */
+   (void) setgid(getgid());
+ #endif
  }
  
  /* Berkeley mail parse and lock mailbox
*** imap/ANSI/c-client/mmdf.c-	Wed Oct 20 14:24:16 1993
--- imap/ANSI/c-client/mmdf.c	Wed Oct 20 14:41:14 1993
***************
*** 50,55 ****
--- 50,59 ----
  #include "rfc822.h"
  #include "misc.h"
  #include "dummy.h"
+ 
+ #ifdef SETGID_HACK
+ extern gid_t egid;
+ #endif
  
  /* MMDF mail routines */
  
***************
*** 1077,1082 ****
--- 1081,1091 ----
    char tmp[MAILTMPLEN];
    struct timeval tp;
    struct stat sb;
+ 
+ #ifdef SETGID_HACK
+   /* Restore effective group ID (probably group "mail") for locking */
+   (void) setgid(egid);
+ #endif
  				/* build lock filename */
    strcat (mmdf_file (lock,file),".lock");
    do {				/* until OK or out of tries */
***************
*** 1148,1153 ****
--- 1157,1167 ----
        sleep (1);		/* wait 1 second before next try */
      }
    } while (i-- && ld < 0 && *lock);
+ 
+ #ifdef SETGID_HACK
+   /* Disable effective group ID (locking is done now) */
+   (void) setgid(getgid());
+ #endif
  				/* open file */
    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
    else {			/* open failed */
***************
*** 1181,1188 ****
--- 1195,1211 ----
    }
    flock (fd,LOCK_UN);		/* release flock'ers */
    close (fd);			/* close the file */
+ 
+ #ifdef SETGID_HACK
+   /* Restore effective group ID (probably group "mail") for unlocking */
+   (void) setgid(egid);
+ #endif
  				/* flush the lock file if any */
    if (lock && *lock) unlink (lock);
+ #ifdef SETGID_HACK
+   /* Disable effective group ID (unlocking is done now) */
+   (void) setgid(getgid());
+ #endif
  }
  
  /* MMDF mail parse and lock mailbox
*** imap/ANSI/c-client/mtest.c-	Wed Oct 20 15:10:13 1993
--- imap/ANSI/c-client/mtest.c	Wed Oct 20 15:17:44 1993
***************
*** 77,82 ****
--- 77,86 ----
    NIL
  };
  
+ #ifdef SETGID_HACK
+ gid_t        egid;
+ #endif
+ 
  void main ();
  void mm (MAILSTREAM *stream,long debug);
  void header (MAILSTREAM *stream,long msgno);
***************
*** 102,107 ****
--- 106,119 ----
    char *suffix;
    struct passwd *pwd;
    struct hostent *host_name;
+ 
+ #ifdef SETGID_HACK
+   /* Save effective group ID (probably the group ID of "mail") */
+   egid = getegid();
+   /* Replace the effective group ID with the real group ID */
+   (void) setgid(getgid());
+ #endif
+ 
    gethostname (tmp,MAILTMPLEN);	/* get local name */
  				/* get it in full form */
    curhst = (host_name = gethostbyname (tmp)) ?
*** imap/ANSI/imapd/imapd.c-	Wed Oct 20 15:17:59 1993
--- imap/ANSI/imapd/imapd.c	Wed Oct 20 15:19:02 1993
***************
*** 110,116 ****
--- 110,120 ----
  extern DRIVER bezerkdriver,tenexdriver,imapdriver,newsdriver,nntpdriver,
    philedriver,dummydriver;
  
+ #ifdef SETGID_HACK
+ gid_t        egid;
+ #endif
  
+ 
  /* Function prototypes */
  
  void main (int argc,char *argv[]);
***************
*** 145,150 ****
--- 149,162 ----
    char *s,*t,*u,*v,tmp[MAILTMPLEN];
    struct hostent *hst;
    void (*f) () = NIL;
+ 
+ #ifdef SETGID_HACK
+   /* Save effective group ID (probably the group ID of "mail") */
+   egid = getegid();
+   /* Replace the effective group ID with the real group ID */
+   (void) setgid(getgid());
+ #endif
+ 
    mail_link (&tenexdriver);	/* install the Tenex mail driver */
    mail_link (&bezerkdriver);	/* install the Berkeley mail driver */
    mail_link (&imapdriver);	/* install the IMAP driver */
*** imap/non-ANSI/c-client/bezerk.c-	Wed Oct 20 14:29:06 1993
--- imap/non-ANSI/c-client/bezerk.c	Wed Oct 20 14:35:33 1993
***************
*** 60,65 ****
--- 60,69 ----
  #include "rfc822.h"
  #include "misc.h"
  #include "dummy.h"
+ 
+ #ifdef SETGID_HACK
+ extern gid_t egid;
+ #endif
  
  /* Berkeley mail routines */
  
***************
*** 1201,1206 ****
--- 1205,1215 ----
    char tmp[MAILTMPLEN];
    struct timeval tp;
    struct stat sb;
+ 
+ #ifdef SETGID_HACK
+   /* Restore effective group ID (probably group "mail") for locking */
+   (void) setgid(egid);
+ #endif
  				/* build lock filename */
    strcat (bezerk_file (lock,file),".lock");
    do {				/* until OK or out of tries */
***************
*** 1272,1277 ****
--- 1281,1291 ----
        sleep (1);		/* wait 1 second before next try */
      }
    } while (i-- && ld < 0 && *lock);
+ 
+ #ifdef SETGID_HACK
+   /* Disable effective group ID (locking is done now) */
+   (void) setgid(getgid());
+ #endif
  				/* open file */
    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
    else {			/* open failed */
***************
*** 1308,1315 ****
--- 1322,1338 ----
    }
    flock (fd,LOCK_UN);		/* release flock'ers */
    close (fd);			/* close the file */
+ 
+ #ifdef SETGID_HACK
+   /* Restore effective group ID (probably group "mail") for unlocking */
+   (void) setgid(egid);
+ #endif
  				/* flush the lock file if any */
    if (lock && *lock) unlink (lock);
+ #ifdef SETGID_HACK
+   /* Disable effective group ID (unlocking is done now) */
+   (void) setgid(getgid());
+ #endif
  }
  
  /* Berkeley mail parse and lock mailbox
*** imap/non-ANSI/c-client/mmdf.c-	Wed Oct 20 14:29:12 1993
--- imap/non-ANSI/c-client/mmdf.c	Wed Oct 20 14:35:57 1993
***************
*** 50,55 ****
--- 50,59 ----
  #include "rfc822.h"
  #include "misc.h"
  #include "dummy.h"
+ 
+ #ifdef SETGID_HACK
+ extern gid_t egid;
+ #endif
  
  /* MMDF mail routines */
  
***************
*** 1158,1163 ****
--- 1162,1172 ----
    char tmp[MAILTMPLEN];
    struct timeval tp;
    struct stat sb;
+ 
+ #ifdef SETGID_HACK
+   /* Restore effective group ID (probably group "mail") for locking  */
+   (void) setgid(egid);
+ #endif
  				/* build lock filename */
    strcat (mmdf_file (lock,file),".lock");
    do {				/* until OK or out of tries */
***************
*** 1229,1234 ****
--- 1238,1248 ----
        sleep (1);		/* wait 1 second before next try */
      }
    } while (i-- && ld < 0 && *lock);
+ 
+ #ifdef SETGID_HACK
+   /* Disable effective group ID (locking is done now) */
+   (void) setgid(getgid());
+ #endif
  				/* open file */
    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
    else {			/* open failed */
***************
*** 1265,1272 ****
--- 1279,1295 ----
    }
    flock (fd,LOCK_UN);		/* release flock'ers */
    close (fd);			/* close the file */
+ 
+ #ifdef SETGID_HACK
+   /* Restore effective group ID (probably group "mail") for unlocking */
+   (void) setgid(egid);
+ #endif
  				/* flush the lock file if any */
    if (lock && *lock) unlink (lock);
+ #ifdef SETGID_HACK
+   /* Disable effective group ID (unlocking is done now) */
+   (void) setgid(getgid());
+ #endif
  }
  
  /* MMDF mail parse and lock mailbox
*** imap/non-ANSI/c-client/mtest.c-	Wed Oct 20 15:26:32 1993
--- imap/non-ANSI/c-client/mtest.c	Wed Oct 20 15:19:55 1993
***************
*** 77,82 ****
--- 77,86 ----
    NIL
  };
  
+ #ifdef SETGID_HACK
+ gid_t        egid;
+ #endif
+ 
  void main  ();
  void mm  ();
  void header  ();
***************
*** 102,107 ****
--- 106,119 ----
    char *suffix;
    struct passwd *pwd;
    struct hostent *host_name;
+ 
+ #ifdef SETGID_HACK
+   /* Save effective group ID (probably the group ID of "mail") */
+   egid = getegid();
+   /* Replace the effective group ID with the real group ID */
+   (void) setgid(getgid());
+ #endif
+ 
    gethostname (tmp,MAILTMPLEN);	/* get local name */
  				/* get it in full form */
    curhst = (host_name = gethostbyname (tmp)) ?
*** imap/non-ANSI/imapd/imapd.c-	Wed Oct 20 15:20:26 1993
--- imap/non-ANSI/imapd/imapd.c	Wed Oct 20 15:21:30 1993
***************
*** 110,116 ****
--- 110,120 ----
  extern DRIVER bezerkdriver,tenexdriver,imapdriver,newsdriver,nntpdriver,
    philedriver,dummydriver;
  
+ #ifdef SETGID_HACK
+ gid_t        egid;
+ #endif
  
+ 
  /* Function prototypes */
  
  void main  ();
***************
*** 147,152 ****
--- 151,164 ----
    char *s,*t,*u,*v,tmp[MAILTMPLEN];
    struct hostent *hst;
    void (*f) () = NIL;
+ 
+ #ifdef SETGID_HACK
+   /* Save effective group ID (probably the group ID of "mail") */
+   egid = getegid();
+   /* Replace the effective group ID with the real group ID */
+   (void) setgid(getgid());
+ #endif
+ 
    mail_link (&tenexdriver);	/* install the Tenex mail driver */
    mail_link (&bezerkdriver);	/* install the Berkeley mail driver */
    mail_link (&imapdriver);	/* install the IMAP driver */

---

From: Andy Poling <[email-masked]>
Date: Thu, 21 Oct 1993 13:06:19 -0400

> towards an effort that adds no user function and is unnecessary with better

Definitely not... pleez.

> of time.  This would fix the problem without requiring that mail readers run

Unfortunately this is not a solution.  You are making a common mistake in
assuming that everyone is running sendmail.  There are at least two other
MTA packages that are as good as, or better then, sendmail (e.g. MMDF and
ZMAILER).  Some sites (like us) handle too large a volume of mail to use
sendmail. 

I say let the system administrator worry about it - this is not a new
problem.  I think your time is much better spent on improving the
interface and user-visible functionality of your MUA.

-Andy

Andy Poling                              Internet: [email-masked]
UNIX Systems Programmer                  Bitnet: ANDY@JHUNIX
Homewood Academic Computing              Voice: (410)516-8096    
Johns Hopkins University                 UUCP: uunet!mimsy!aplcen!jhunix!andy

---

From: Mark Crispin <[email-masked]>
Date: Thu, 21 Oct 1993 22:17:18 -0700 (PDT)

> Could it be possible to use some small external program from pine to

That was considered many years ago.  One problem with doing this is that Pine
is no longer self-contained; you now have to install two programs.

Plus, this doesn't help the case where Pine is user-installed and maintained,
since presumably that external program will run with set[gu]id privileges and
most system managers don't allow random programs to be privileged.