Cover V05, I10
Article
Figure 1
Figure 2

oct96.tar


Techniques for Simulating Multiple Group Ownership

Doug Morris

How often as a system administrator have you wished you could control access to data files and directories with some of the same ease and flexibility afforded by your favorite DBMS (Database Management System)? Specifically, how often have you wished you could provide different modes of access (READ/UPDATE) to selected sets of users without replicating the data for each set of users? You can do this on any UNIX system. Using the techniques described in this article, you will be able to accomplish the above without incurring the expense, overhead, and hassle of moving your data into a DBMS.

As a system administrator, you would like to give two different groups of users (the READ group and the UPDATE group) different permissions to the same data directory (DATA).You would like each user in the READ group to have read-only access to the files contained within DATA. Users in the UPDATE group should have both read and write access to the files contained within DATA, and users not in either READ or UPDATE (other/world) should have no access to DATA.

At first, the solution may appear straightforward:

1) Define the two groups READ and UPDATE in the group file;

2) Use chgrp to assign the group ownership of DATA, and chmod to assign the permissions.

The catch is that DATA can only have one group owner, either READ or UPDATE, not both.

If you try the above method starting with the READ group, the command sequence:

chgrp -r READ DATA
chmod g=rx DATA
cd DATA
chmod  g=r *

works correctly for the READ group. It assigns the group owner of READ to the DATA directory and to the files under DATA by performing a recursive chmod (-r option) on the DATA tree. It also grants read and search access to the READ group to the directory DATA, and read access to all files immediately under DATA.

The problem arises when you continue with the UPDATE group. You get stopped by the first command:

chgrp -r UPDATE DATA

This changes the group owner from READ to UPDATE; thus, the READ ownership and permissions are lost. You could alternatively duplicate the DATA directory and its files, and let the READ group own the original and the UPDATE group own the copy. But, keeping the two separate copies in sync would be difficult and cumbersome.

If your UNIX flavor supports Access Control Lists (ACLs), you could extend the mode permissions with the following permit rules:

For DATA,

permit rwx g: UPDATE

and for all files under DATA,

permit rw g: UPDATE

ACLs can be handy. They can be used to supplement mode permissions and extend/deny access to specific users or groups of users. Unfortunately, most UNIX systems to not support ACLs. Even if they are supported, ACLs usually do not extend across NFS mounts and may be difficult to maintain. For example, each file added under data may require additional action to assign the ACL if there is no way to define inheritance.

Fortunately, there are techniques using control directories that are simpler, possibly easier to maintain, and extensible to any Unix system. The concept behind these techniques is simple. Use a control directory as a barrier to cut off access to the underlying subtree. If the control directory is owned by READ with group permissions of g=rx, o=, then only the owner and users in the READ group will have access to the files or directories in the underlying subtree. All other users will have no access, because search permission is missing for other/world (o=).

Technique 1 - Single Control Directory with Dual Memberships

For this technique, the UPDATE group must be defined differently. UPDATE will not be a group unto itself, instead it will be a permission attribute defined in terms of two new groups READ and WRITE.

The new READ group will be the union of the natural READ group and the new WRITE group. The new WRITE group will be identical to the natural UPDATE group. Using these groups, define a control directory (CONTROL) with a group owner of READ and permissions of g=rx, o=.

cd ../DATA
mkdir CONTROL
chgrp READ CONTROL
chmod g=rx, o=    CONTROL

Directly underneath the CONTROL directory is the DATA directory. For the DATA directory and its subtree, define the group owner to be WRITE with permissions of g=rwx, o=rx for DATA, and g=rw, o=r for all files within DATA.

chgrp -r WRITE DATA
chmod g=rwx, o=rx DATA
cd DATA
chmod g=rw, o=r *

The above structure (illustrated in Figure 1) implements the desired solution, in that, no user outside the READ or WRITE groups has any access to the DATA subtree. Users in the READ group have group search access to the CONTROL directory, so they may reference the DATA subtree. These users obtain read access to the DATA subtree through the permissions assigned to other/world. The group permissions do not apply because they are not members of the WRITE group; however, they are by definition members of other/world.

Users in the WRITE group have search access to the CONTROL directory via the permissions assigned to other/world. They obtain read and write access to the DATA subtree via the group permissions for WRITE.

This technique works best on UNIX systems derived from BSD. BSD supports concurrent participation in multiple groups though an extension called the supplementary group set. This supplementary group set is simply an array of group ids (gids) initialized at login to contain the gids of all groups in which the login user is a member. Note that it may not be possible to accommodate all groups of which the user is a member. The array size is kernel defined (NGROUPS_MAX parameter) and usually fixed at 16 to 32 entries - 16 is the most common value because it is the maximum number officially supported by NFS.

The supplementary group set is inherited by each process and defines all gids for which group permissions are enabled. On systems not supporting the supplementary group set, the array size is essentially one - the effective gid. The effective gid can be dynamically changed via the newgrp command, which takes a group name or gid as its argument. For UPDATE users to obtain write access on these systems, they would have to do the following:

newgrp READ
cd CONTROL
newgrp WRITE

This change of group is necessary because concurrent membership is not active as in BSD systems.

Another useful feature of BSD systems is group inheritance. If you issue the command:

chmod g+s DATA

then any file or directory created under DATA will automatically inherit the group owner of WRITE instead of the user's primary or effective group.

For systems not supporting supplementary groups, or in cases where dual membership in the READ and WRITE groups is not desirable, the following technique may be more useful.

Technique 2 - Dual control directories with single memberships

For this technique, define the READ and UPDATE groups according to their natural definition, and define two separate control directories CONTROL_R and CONTROL_U with a common parent of PROTECT. Let the READ group be the group owner of CONTROL_R, and the UPDATE group by the group owner of CONTROL_U. Assign permissions of g=rx, o= to CONTROL_R, and g=rwx, o= to CONTROL_U.

cd PROTECT
mkdir CONTROL_R CONTROL_U
chgrp READ CONTROL_R
chgrp UPDATE CONTROL_U
chmod g=rx, o=   CONTROL_R
chmod g=rwx, o=   CONTROL_U

Now the tricky part: move the directory DATA under CONTROL_R and let DATA be owned by UPDATE with permissions of g=rwx, o=rx. Similarly, let all files under DATA be owned by UPDATE with permissions of g=rw, o=r. Create a hard link to DATA under the CONTROL_U directory (on many systems you will need to be root to do this).

cd CONTROL_R
mv <full pathname of DATA> DATA
chgrp -r UPDATE DATA
chmod g=rwx, o=rx DATA
cd DATA
chmod g=rw, o=r *
cd  <full pathname of PROTECT>/CONTROL_U
ln -f ../CONTROL_R/DATA DATA

CONTROL_R and CONTROL_U are now parents of the same directory, DATA. The permissions of the control directories and DATA (illustrated in Figure 2) are such that users in the UPDATE group can obtain read or write access through the path PROTECT/CONTROL_U/DATA, and users in the READ group can gain read access through the path PROTECT/CONTROL_R/DATA. All other users have no access, and neither group can gain access though the other's path. Note that the hard link to the directory was created by using the -f option of the ln command. This option is supported by SunOS and other UNIX systems, but may not be supported or interpreted in the same way on all UNIX systems (i.e., the GNU version of ln uses the -d or -F options to force a hard link to a directory). Unfortunately, not all UNIX systems support hard links to directories, SGI Irix and Linux are two common examples. For these systems, the same technique can be used, but the files in the directory will have to be linked individually.

Summary

I have described techniques that will allow you to control access to data files and directories with some of the same ease and flexibility afforded by your favorite DBMS - without the hassle, and expense of moving the data to a DBMS.

Both of the described techniques were used to simulate a form of multiple group ownership. These techniques are useful because they allow you to define separate groups with different access rights to the same data (typically one group will be read-only, and the other will be read-write).

Technique 1 exploits the concurrent group membership allowed on BSD systems. It is straightforward and easy to implement using intersecting READ and WRITE groups (UPDATE access is granted though dual membership in both the READ and WRITE groups).

Technique 2 is suited to conventional UNIX systems or to cases in which intersecting groups are not desirable. This technique is more complicated to implement and requires the construction of a hard link to a directory (hard links are usually not allowed to span physical partitions, and directory hard links may not be supported on all systems). It also requires the construction of two control directories with differing group ownerships and access permissions. Users in either the READ or UPDATE group must specify the correct path though the proper control directory or access will be denied.

About the Author

Doug Morris has a B.S. in Mathematics and an M.B.A. in Management Information Systems. He is a UNIX enthusiast and long-time Open Systems advocate. He has been an active participant in XOpen, including holding an elected office on the XOpen User Council Executive. He has held various positions in technology evaluation and management at several Fortune 500 companies, including his current position as a Systems Specialist/Software Engineer at a major international oil company. He can be reached at his personal email address of damorri.msn.com.