From: zinar@luna.math.ucla.edu (Richard Zinar)
Newsgroups: comp.unix.questions
Subject: Setgid confusion
Date: 24 Jul 92 21:22:49 GMT
Organization: UCLA Mathematics Department

Hello ...

  We're experiencing a problem with a locally developed piece of
  code which makes use of the "setuid" and "setgid" features of UNIX.
  I've enclosed a program which recreates the problem.  The executable
  program has the following settings:

        owner:  submit (uid 56)
        group:  turnin (gid 22)
        perms:  6711 (-rws--s--x)

  and is run with the current directory having:

        owner:   p10aaedh (uid 3145)
        group:   student  (gid 20)
        perms:   705 (drwx---r-x)

  The getwd() call fails, and produces the message "can't stat .", 
  and the following stat () call also fails.

  The program is running on SunOS 4.1.1 on a SparcStation 2.
  The program worked successfully on our old machines running SunOS 3.5,
  but reviewing the documentation in "System Services Overview" didn't
  shed any light on why it's no longer working.  The printed real and
  effective UIDs and GIDs have the values I would expect to see, but 
  it doesn't seem to affect the outcome of the getwd() call.

  The file system in which the directory passed to stat() is
  located has mount options "rw,quota,grpid" (and "suid" is documented
  as a default option).  Note that the program is NOT trying to access
  an NFS-mounted file as root (or so I believe, anyway).

The program follows:

   #include <sys/param.h>
   #include <sys/types.h>
   #include <sys/stat.h>
   #include <stdio.h>
   #include <errno.h>
   
   main ()
   {
      char         pname[MAXPATHLEN];
      struct stat statbuf;
   
      int  real_uid, eff_uid;
      int  real_gid, eff_gid;
   
      extern char *getwd ();
   
   
      real_uid = getuid ();
      real_gid = getgid ();
      eff_uid  = geteuid ();
      eff_gid  = getegid ();
   
      printf ("Real uid: %d\n", real_uid);
      printf ("Real gid: %d\n", real_gid);
      printf ("Effective uid: %d\n", eff_uid);
      printf ("Effective gid: %d\n", eff_gid);
   
      setgid (getegid ());
      setuid (geteuid ());
   
      real_uid = getuid ();
      real_gid = getgid ();
      eff_uid  = geteuid ();
      eff_gid  = getegid ();
   
      printf ("Real uid: %d\n", real_uid);
      printf ("Real gid: %d\n", real_gid);
      printf ("Effective uid: %d\n", eff_uid);
      printf ("Effective gid: %d\n", eff_gid);
   
      if ( getwd (pname) == (char *) 0 )
         printf ("Error: %s\n", pname);
      else
         printf ("Current directory: %s\n", pname);
   
      if ( stat (".", &statbuf) != 0 )
         perror ("Stat call failed");
      else  {
         printf ("Current directory's uid: %d\n", statbuf.st_uid);
         printf ("Current directory's gid: %d\n", statbuf.st_gid);
      }
   
      exit (0);
   }
 
 
The  program output is as follows:
 
   Real uid: 3145
   Real gid: 20
   Effective uid: 56
   Effective gid: 22
   Real uid: 56
   Real gid: 22
   Effective uid: 56
   Effective gid: 22
   Error: getwd: can't stat .
   Stat call failed: Permission denied
 
   In an edited version of the above test program, I used the getgroups()
   system call to check the supplementary group ID(s) after the setuid and
   setgid calls had been made, and found that it contained only
   gid 20 (student), and not gid 22 (turnin), which seemed surprising.
   Any insights into this behaviour would be greatly appreciated ...
 
 			              Richard Zinar
                                      Computing Support Staff
                                      UCLA Mathematics Department
                                      Email: zinar@math.ucla.edu