Aucbvax.4493
fa.unix-wizards
utzoo!decvax!ucbvax!unix-wizards
Fri Oct 16 01:11:29 1981
S[UG]ID files and [sg]et[re][ug]id() system calls
>From decvax!ittvax!swatt@Berkeley Thu Oct 15 21:56:23 1981


       From decvax!ucbvax!MBM@MIT-XX Wed Oct 14 07:30:53 1981
       Date: 13 Oct 1981 2214-EDT
       From: MBM at MIT-XX
       Subject: Re: S[UG]ID files and s[re][ug]id() system calls
       To: decvax!ittvax!swatt at UCB-C70
       In-Reply-To: Your message of 8-Oct-81 2028-EDT

       When you say " we made the user - group relationship a hierarchy rather
       than an overlay" does that mean you could have the same uid representing
       2 different usrs in 2 different groups?  This would seem to require a 32
       bit number to uniquely identify a user...
       I was also thinking of having a hierarchy of groups , so that perhaps
       lower group numbers became more and more powerful, srt of like multics
       rings ... is that what you meant?
       --a little confused
       -------
[ This was originally a simple mail response to the above query, but
 the completed length of it is in excess of what I have been able to
 get through the ARPA gateway as mail, so I am sending it out as
 news.
]

Sorry for the confusion; I'll try to make this description complete.
The normal UNIX notion is that a process has both a "user id" and an
unrelated "group id" at the same time.  Each file has "userid" and
"groupid" attributes which are set to the effective user and group ID's
of the process which creates the file.  Each file also has three sets
of access permissions:  one for "owner", one for "group", and one for
"other".  The superuser is userid 0, and always has permission to do
anything.  Checks on file permissions are done by the following
method:

       IF caller's userid == 0 THEN
               return OK
       ENDIF
       IF caller's userid == file's userid THEN
               check "owner" permissions
       ELSEIF caller's groupid == file's groupid THEN
               check "group" permissions
       ELSE check "other" permissions
       ENDIF

In old V6 UNIX the ID information was kept in a byte; V7 uses 16-bit
words.  The painful issue was not the kernel structures to keep track
of process permissions, but the disk space for the inodes to record
file ownership.  Under V6 UNIX filesystems and the standard permission
checking, you could only have 256 unique users and 255 unique groups.
What we wanted was a way to have more unique users without restructuring
the disk filesystem.

When I said the user - group relationship became a hierarchy I meant
that there were 256 groups, each one containing 256 users.  The two IDs
TOGETHER determined permissions, making a total of 65536 user ID's.
Thus if I were user #27 in group #100, I would share group permissions
with anyone else in group #100, but be considered as an "other" to
anyone in any other group.  Or, to draw a picture:

   grp #0            grp #1      ...    grp#254           grp#255
   / | \            / |    \            / |  \            / |   \
  /  |  \          /  |     \          /  |   \          /  |    \
#0  #1...#255    #0  #1 ... #255     #0  #1 ...#255    #0  #1 ... #255


The SUPER-user (we called it the "ultrauser") would be user id #0 in
group #0.  Userid #0 in any other group would be the group superuser
for that group, but just an ordinary user in any other group.  There
was no multics-like ring system, except that we tended to make users
in the lower-numbered groups own the important system files.

[ We even had a special status group reserved for Nobel Lauriates,
 Dennis Ritchie and Ken Thompson, but sadly none of them ever
 requested an account ...
]

The new permission checking was done according to the scheme:

       IF caller's userid == 0 AND caller's groupid == 0 THEN
               return OK
       ENDIF
       IF file's groupid == caller's groupid THEN
               IF caller's userid == 0 THEN
                       return OK
               ENDIF
               IF file's userid == caller's userid THEN
                       check "owner" permissions
               ELSE
                       check "group" permissions
               ENDIF
       ELSE
               check "other" permissions
       ENDIF

The "newgroup" command went away as a result of this, although we
did think of having a special user id "guest" in each group which
would sort of accomplish the same effect.

It was also necessary to change the treatment of S[UG]ID files
so that:

       SUID only files would be honored only for callers whose groupid
       was the same as the groupid of the file.

       SUID+SGID files would work always.

       SGID only files would be honored only for callers whose userid
       was the same as the userid of the file.  This last is sort of
       a strange special case.  It's only use was for system privileged
       programs which could be set to work ONLY for people who were
       already group superusers (a security feature of dubious value).

It was therefore possible for someone to write a program which would
bestow his permissions ONLY on members of the same group, which I
think does have real value.

However the main reason for the change was not to allow group
superusers, but to allow more than 256 unique user ID's.  There is
another scheme, which may have been adopted by Interactive Systems (I
am fairly sure it has been proposed by Peter S.  Langston) for their
PWB/PDP-11 systems, which involves using the top 5 or six bits of an ID
word as the groupid and the remaining bits as the userid.  This
method would allow more unique userid's without disturbing the
interpretation of the groupid (although allowing fewer groups).

Amazingly little had to be changed in the kernel or systems programs
to make all this work.  Very few programs really know how to determine
permissions; they use the "access" system call if they're privileged,
simply attempt the operation if they're not.  All the kernel permission
checking is concentrated in a few routines.

I have never known a UNIX installation to use the standard user-group
system in any truly useful way, so we didn't consider our changes as
giving up anything.  It seems clear to me that without some special
privileged user for each "group" its usefulness for project
organization is very limited.  I can "newgroup" to any group which
lists me as a member in the group file "/etc/group".  To change this
requires editing the file (it is only writable for "root").  There is
also a provision in this file to demand a password from anyone wishing
to "newgroup" to a group, but just who should have the right to set the
password is arguable.  Now the first problem could easily be solved by
writing a SUID program to edit the group file and allow normal users to
change the list of users permitted to join a group, but it is again
unclear to me just who should be allowed to use this program.
Effectively, to administer a group's account, you have to be root.

       - Alan S. Watt (decvax!ittvax!swatt)

-----------------------------------------------------------------
gopher://quux.org/ conversion by John Goerzen <[email protected]>
of http://communication.ucsd.edu/A-News/


This Usenet Oldnews Archive
article may be copied and distributed freely, provided:

1. There is no money collected for the text(s) of the articles.

2. The following notice remains appended to each copy:

The Usenet Oldnews Archive: Compilation Copyright (C) 1981, 1996
Bruce Jones, Henry Spencer, David Wiseman.