Cover V05, I09
Article
Figure 1
Figure 2
Figure 3
Figure 4
Listing 1
Listing 2
Listing 3
Sidebar 1

sep96.tar


Creating User Islands

Arthur Donkers

System administration for any group of users is often a challenge. If, however, you are one of those system administrators who have to keep a development machine up and running, you are familiar with the special problems that different groups of developers can create on your machine. They seem to enjoy wreaking havoc in each other's environments and can cause trouble for unsuspecting users. What you need is a way to keep these people in their part of the filesystem and deny them access to other people's directories. Essentially, you need to create islands of users without filesystem rowboats. This article will show you how to protect users from each other with standard UNIX file permissions.

What I describe here is a system of barriers between different groups of cooperating users on the same machine. This approach should not be confused with tight, government-level security. If you have a different need for your machine, you may resort to dedicated, security-based filesystems that offer complete audit trails, access control lists, and other features. Such filesystems are compliant with U.S. government security standards (C2 or even B1, as described in the so-called Orange Book standard) and are usually used only for special purposes on compliant systems.

Island Topography

Most readers are familiar with the typical structure of the UNIX filesystem, the user-group-other set of file permissions, and the concept of setuid and setgid special permissions. If you are new to UNIX or feel rusty on your UNIX filesystem structure, the accompanying sidebar ("UNIX Filesystem and Permissions Revisited") provides background on the features that the system outlined here will take advantage of. You can use this filesystem protection to create a secure environment for the developer group to work in. But, before you can start writing code, you first need to know exactly what an environment should look like, who can use it, and more importantly, who should not be able to access it.

Environment Specifications

The basic assumption is that your development system supports multiple groups of developers, each group working on different projects. The environment should provide access only to the group of developers who are working on a particular project's code. At first, the solution appears trivial. You can combine sets of developers into a group and use the group id as an entrance key into each project's development area. The problem, however, is that developers tend to work on more than one project at any given time. So, if you add them to the different development groups, they can also access the different development areas at the same time. This might lead to problems, such as inadvertently deleting files in the wrong directory.

Although setgid and setuid bits should be used with considerable caution, they provide a solution to the problem of keeping developers on their own island. You can use these features in combination with a special change-development-area program, setdev (Listing 1), and change users' group ids when they enter a development area. Additionally, if you give each development area a unique owner and group id, the problem is solved. Confused? Figure 1, the process of changing ids is shown graphically.

Here is a simple example: User 1 logs in and automatically enters his or her home directory, using his or her user and group id. This user first needs to work on project 1 and calls a special program, setdev, to enter that development area. By doing so, the user changes his or her currently active group id to devgrp1 and is automatically transferred to the home directory of development area 1. All files in this area are owned by the user id devown1 and group id devgrp1. All applicable files and subdirectories in this area are group writeable, so a developer can create and edit files as needed.

Furthermore, each developer keeps his or her own identity (the user id assigned at login), so each developer can create a private working directory in which he or she can store workfiles, temporary copies of source code, and so on. This user id is also used when checking out sources from the Code Management System. This code management system (e.g., RCS) uses the user id to reserve a file and lock it from use by other users. When the user is finished working on that piece of code, the code is checked into the source storage, and other users can access it again. This locking is normally based on the user id, and if all developers were mapped onto the same, special development id, this feature would be lost.

All files in the development area are owned by a special user, called devown1. This user has a special status, and normally has the daunting task of doing code freezes and releasing a specific version of the code. The user can do so by freezing the code in the code management system, making a read-only copy, and storing it in a tar archive. The archive can then be copied into a special staging area in which it is unpacked and recompiled. The resulting binaries, libraries, or other products can then be distributed to anyone who needs them.

Two security issues are essential to keep this setup working. First, to prevent any unwanted visitors from entering a development area, all access rights for "other" users should be cleared. By doing this, users who are not devown1 or members of devgrp1 cannot access the files in this area. Second, users should not be permanently assigned as members of a particular developer group by their /etc/passwd entries. Access to development areas must be controlled by use of the setdev program.

The layout of all development areas is usually the same, so creating such an area can be done with a shell script. This helps you build a consistent development environment for all your projects and should make it easier for people to change from one project to another.

Implementation

The implementation of the setdev program has a few interesting details. First, to change the group id of the caller, you would expect to use a setgid program. This however is not true. The setdev program must be able to change the group id of the user to a value depending on the development area selected. So, instead of setgid, it will be a setuid program. And, to be able to change to a group id that the user is not part of, the setdev program must be setuid to root, as root is the only user with authority to change into any identity.

Because of the security issues resulting from setdev being setuid-root, it is implemented in C rather than in shell or another interpreted language. Most interpreted languages allow you to use stdin as the source of statement to be interpreted, so if a setuid shell script is used, you can feed it any command you like and quickly become superuser by starting a setuid root subshell. The setdev program also performs various sanity checks before actually changing the caller's group id.

When a user starts setdev, the first thing the program does is save the id of the original user. The program needs that to return to after it has changed group ids. Additionally, setdev requires a control file to determine whether a user is allowed to enter a development area. (See Listing 2.) The name of this control file is /etc/setdevd, and it resembles the passwd file:

group_name:group_home_directory:group_members

The group_name is a short, unique name that identifies the development group. The group_home_directory is the location of the root of this development area. All developers in that particular group will be placed here after calling the setdev program. Finally, group_members defines which users are allowed to do a setdev to that particular development group and its respective file area. File permissions for setdev program are shown in Figure 2, and the results of calling the setdev test are shown in Figure 3.

The creation of a development area is done with a shell script called createdev, shown in Listing 3. This script should only be executable by root, because it does not do extensive checking. Figure 4 shows a fresh development area after running createdev.

Conclusions

The solution and accompanying programs are simple. The programs have worked well for me on various projects and can help you isolate different development groups from each other. Several obvious improvements exist, such as support for the code staging area and built-in support for a code management system. For my use, I have chosen to keep it simple.

About the Author

Arthur Donkers graduated from the Delft University of Technology with a degree in Electrical Engineering and a major in Computer Architecture. Since then he has worked for a number of major software houses in the Netherlands and participated in a number of major projects. His primary field of interest in these projects has been, and still is, datacommunications. With the growth of the Internet, the need for network security grows as well. Therefore, he now operates as an independent consultant in the field of network security. For the past four years, he has worked as an independent consultant for his own company, Le Reseau (French for "The Network," http://www.reseau.nl).