next up previous
Next: 2.8 Processes and Process Groups Up: 2. Environmentally Friendly I/O Previous: 2.6 Files, Links, and Directories

2.7 User and Group Identities

The routines in this set are useful only on systems that support the notion of users and groups thereof, and are most useful on systems that distinguish ``real'' from ``effective'' users and groups. On systems with no such support, the ``getters'' should be implemented to return 0, and the ``setters'' should act as no-ops: *

uid := getuid();    -- get real user id
uid := geteuid();   -- get effective user id
gid := getgid();    -- get real group id
gid := getegid();   -- get effective group id
setuid (uid);       -- set at least the effective user id
setgid (gid);       -- set at least the effective group id
The setuid (setgid) procedure sets the real and effective user (group) id if the effective caller is the superuser. Otherwise, the effective id is set to the requested value if it matches the real id or it matches the id associated with the file to which exec was last applied prior to starting the SETL run-time and that file has the appropriate (``allow set-user-id'' or ``allow set-group-id'') bit set in order to permit just such a change of effective id. If the requested identity change cannot be performed, last_error (see Section 2.13 [Normal and Abnormal Endings]) will show the error. If the call succeeds, however, the process acquires the privileges of the effective id. It is not a good idea to make the executable file of a public SETL interpreter allow setting of the user or group id like this, or any user will be able to execute arbitrary SETL programs using the user or group identity attached to the interpreter file, simply by inserting a setuid or setgid call.

An example of a superuser process that needs to be able to change ``down'' to an ordinary user process is a login daemon such as rlogind or a periodic process-spawning daemon such as crond. It is also sometimes convenient for one user to own a program which, when run by another user, has available the privileges of both, setuid being used to toggle the effective user id back and forth between the two users as necessary. For example, when my students at Lehigh University submit their programming assignments, they unwittingly run a SETL program which assumes the identity of the submitter (the real user id) when it picks up files from their private directories, and takes on my identity (the effective user id, the owner of the script from which the SETL program is launched) when it squirrels an image of the submitter's files away in a private area allotted by me. No superuser privileges are required to implement such a scheme, though of course some care had to be exercised in designing those parts of the program which execute ``as me'', so as to avoid such perils as allowing one student to consume all my disk space and thereby preventing other students from submitting their assignments.

The flags attached to a file depend on the filesystem hosting the file, and their exact interpretation depends on the host operating system. However, if the filesystem maintains, for each file, 3 ordered sets labelled User, Group, and Others, each set consisting of 3 bits labelled Read, Write, and Execute, then there is a Posix-based routine for controlling an environmental mask value which determines which bits are set when files are subsequently created by the SETL program: *

mask := umask();   -- get file creation bit-mask
umask (mask);      -- set file creation bit-mask
The 9 bits represented by octal 666 are OR'ed with the inverse of this mask to determine what bits are initially set in new files. For example, a user who wants new files to be created with read and write access for the user (the owner), and read-only access for everyone else, might code: *
umask (8#022#);    -- User {rw-}, Group {r-}, Others {r-}
This environmental file creation mask is inherited by processes, and every Unix shell in common use has a built-in umask command that calls the corresponding Unix umask function. On systems where this mechanism is absent, SETL implementations are expected to treat the umask setter as a no-op, and have the getter return 0.

The use of octal is such a natural and customary choice here that some programmers even tend to use it on the system command that normally manipulates these bits, chmod. For example, if it is desired to make a file foo universally executable after it has been created with the ``octal 644'' permissions suggested by the example above, this can be done with either of the following calls: *

system (`chmod +x foo');    -- merge 8#111# with foo's current bits
system (`chmod 755 foo');   -- set foo's bits to {rwx}, {r-x}, {r-x}
The chmod command or subroutine can also be used to set the bits which cause the effective user or group id to be changed to that of the file owner (as opposed to the process owner) when the file is used to replace a process image by exec, thus giving the executing program the rights of the file owner together with the ability (via setuid or setgid) to switch between those and the rights of the process owner. For example, if you want other people to be able to update your database only through your foo command, you might execute: *
system (`chmod u+s foo');   -- make foo allow setuid to thee or me

next up previous
Next: 2.8 Processes and Process Groups Up: 2. Environmentally Friendly I/O Previous: 2.6 Files, Links, and Directories
David Bacon