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).
|