Range-mapping and cloaking are features that offer additional access-control mechanisms for exporting NFS volumes. We designed these features with three goals: compatibility, flexibility, and performance.
First, we are compatible with all NFS clients by requiring no client-side or protocol changes. Range-mapping and cloaking are performed entirely by the NFS server. The server forces a behavior on the client that maintains compatibility with standard Unix semantics. Second, we provide additional flexible access-control mechanisms that allow both users and administrators to control who can view or access files. We allow administrators to mix standard Unix and cloaking semantics to define new and useful policies. Third, our design is economical and efficient. We utilize hash tables and caches to ensure good overall performance.
Traditionally, NFS supports two simple forms of credential mapping called root-squashing and all-squashing. Root-squashing allows an NFS server to map any incoming UID 0 or GID 0 to another number that does not have superuser privileges, often -2 (the nobody user). All-squashing is a Linux NFS server feature that allows the server to map all incoming UIDs or GIDs to another number, representing a user or group with minimal privileges (e.g., -2).
These two crude forms of credential mapping are not sufficient in many situations. First, there is no way to map arbitrary ranges of client IDs to server IDs. Therefore, squashing is not sufficient in cases where it is desirable to map to more than a single ID. Second, it is useful in some cases to map one set of IDs while squashing all others. For example, if the file system was exported to a client where only UIDs 400-500 should be able to access their files on the server, then it is desirable to assure that all other UIDs coming from the client are squashed to -2.
Range-mapping allows greater flexibility in mapping credentials. Range-mappings are defined per export (exported file system) and allow the NFS server to restrict or map any set of an NFS client's credentials to the corresponding set on the server. Figure 1 shows an example of several range-mappings. First, client UID 100 is mapped to server UID 10 (1-to-1). Second, client UIDs 400-500 are mapped to server UIDs 200-300 (N-to-N), respectively. Third, client UIDs 800-900 are mapped to server UID 517 (N-to-1); this case is also called squashing. For N-to-1 mappings, the server reverse-maps the single server UID to the first corresponding client UID in the squashed range: server UID 517 is reverse-mapped to client UID 800 in Figure 1. Finally, the arrow with a slash through it means that all other UIDs are restricted (squashed to -2).
Range-mapping is done bidirectionally. Forward mapping is done when a client sends a request to the NFS server and the server maps the user's client UID and GID to the corresponding server UID and GID. Reverse mapping is done when the server responds to the client (i.e., when returning file attributes) and must map the user's server UID and GID back to the corresponding client UID and GID.
Range-mapping definitions are specified per export in /etc/exports as part of the option list. To provide human-readable formatting of the range mapping definitions, we extended the file's format to support whitespace and line continuation. The syntax for the range mapping option is as follows:
The first option in rmap_def specifies whether the definition applies to UIDs or GIDs. The rm-low, rm-high, and lc-low values specify the remote lower bound, remote upper bound, and local lower bound ID values, respectively. The client ID range rm-low to rm-high is mapped to the server's ID range lc-low as follows:
A one-to-one mapping from ID rm-low on the client to ID lc-low on the server is performed if rm-high is not specified or is equal to rm-low.
The map or squash option specifies that an N-to-N, or N-to-1 ID mapping is being performed, respectively. The following example shows a single range mapping definition:
The definition above specifies two range-maps for clients who are members of the example.com domain and are accessing the /home volume. First, client UIDs 100-250 will be mapped to server UIDs 12314-12464. Second, client GIDs 100-200 be squashed to server GID 6000.
Range-mapping is a superset of root-squashing and all-squashing. Root squashing is a feature of NFS that allows the NFS server to map the root UID (0) and GID (0) to the nobody UID (typically -2) and nobody GID (typically -2). The following example shows how to perform root squashing using range-mapping:
All-squashing is a feature supported in Linux that maps all client UIDs and GIDs to -2. All-squashing may be done with range-mapping as follows:
File-cloaking is a mechanism that abstracts the concept of file permissions to allow data to be hidden. With file-cloaking, if a file is not visible then it is not accessible. When a request is made to access a file or list a directory, file-cloaking uses the NFS credentials, file protection bits, and cloaking-mask to determine access and visibility.
Figure 2 shows how file-cloaking works. The NFS credentials are checked against the owner of the file. If the credentials match then the file is visible. Otherwise two checks are done, each with an AND between the cloaking-mask and the file's protection bits. The first check is done if the credentials have group ownership on the file. The group RWX bits of the cloaking-mask are ANDed with the file's protection bits. The second check is done with an AND between all the bits in the cloaking-mask (excluding the group rwx bits) and the file's protection bits (excluding the group and user bits). If the result of either AND is non-zero and the SHOW bit of the cloaking-mask is set then the file is visible; else if the SHOW bit is unset then the file is cloaked. The inverse behavior takes place if the result of the AND is zero. In this way, the SHOW bit can determine whether files are visible or cloaked by default, allowing the other mask bits to reverse the default behavior.
Tables 1 and 2 illustrate the concept of cloaking and provide some examples of useful cloaking configurations. Table 1 shows a sample of files owned by two different users: joe and ezk. The permissions for each file are listed including the SETUID, SETGID, and sticky bits. User joe belongs to the src group, and user ezk belongs to the src and fac groups. Table 2 shows a visibility/accessibility matrix of the files listed in Table 1 for eleven useful cloaking masks. In Table 2, ``A'' implies ``v'' and the ``+'' or ``-'' preceeding the mask sets or clears the mask's SHOW bit, respectively. Next, we describe a few of the examples in Table 2.
With mask +000, the administrator enforces a strict policy that users can only see their own files. On the other hand, with mask -077 the administrator chooses a policy that allows users to decide if their files should be hidden or not by setting the group and world bits. To hide a file from everyone, the user may set any of the ``other'' bits. To hide a file from group members, the user may set one of the group bits. Note that this mask is non-intuitive because it restricts access by performing an action that would normally increase others' access. Also, note that this option is not fail-safe. If the administrator changes the export option hidden files might not only be visible, but also accessible.
The next to last two lines in Table 2 show that cloaking allows the server to enforce the client-side nosuid and nosgid mount options. The nosuid and nosgid options are achieved by cloaking using the masks -400 and -200, which translate to hide SETUID and hide SETGID files, respectively. Note that cloaking here is more restrictive than the nosuid and nosgid options. These options allow files to be executed, but without their set-bits. Cloaking hides such files and thus disallows their execution altogether.
Another example is the mask -002, which hides all world-writable files. This mask can be especially useful on multi-user systems to protect layman users from leaving their files world writable. In this scenario the administrator enforces a policy on the systems users.
Cloaking definitions are specified with range-mappings in the /etc/exports file. The syntax for cloaking definitions is as follows:
As with range-mapping, the first option specifies whether the definition applies to UIDs or GIDs. Next, mask is a 10-bit field for defining the cloaking policy. Figure 2 shows the different bits comprising the mask.
The range lc-low to lc-high is the range of server IDs to cloak based on the policy given by the mask. If lc-high is omitted, then the definition applies only to the server ID lc-low. The following example shows a cloaking definition:
In this example, there are two cloaking definitions. The first places the restriction for UIDs 500-1000 that only the owners may see or access their files. That is, files on the server owned by UIDs 500-1000 cannot be seen or accessed by any user other than the owner. The second definition states that files owned by UIDs 100-200 are only visible if there is world access to them, or if there is group access to them and the user listing the file belongs to the group of the file.