Authentication errors may occur when trying to mount a filesystem, in which case the superuser is in too many groups. Errors may also occur when a particular user tries to access files on the NFS server; these errors result from any NFS RPC operation. Pay particular attention to the group file in a heterogeneous environment, where the NIS-managed group map may be appended to a local file with several entries for common users like root and bin. The only solution is to restrict the number of groups to the smallest value allowed by all systems that are running NFS.RPC: Authentication error
Changing the UID for nobody from 60001 to 0 allows the superuser to access all files exported from the server, which may be less restrictive than desired. Most NFS servers let you grant root permission on an exported filesystem on a per-host basis using the root= export option. The server exporting a filesystem grants root access to a host or list of hosts by including them in the /etc/dfs/dfstab file:share -o ro,anon=0 /export/home/stuff
The superuser on hosts bitatron and corvette is given normal root filesystem privileges on the server's /export/home/work directory. The name of a netgroup may be substituted for a hostname; all of the hosts in the netgroup are granted root access. Root permissions on a remote filesystem should be extended only when absolutely necessary. While privileged users may find it annoying to have to log into the server owning a filesystem in order to modify something owned by root, this restriction also eliminates many common mistakes. If a system administrator wants to purge /usr/local on one host (to rebuild it, for example), executing rm -rf * will have disastrous consequences if there is an NFS-mounted filesystem with root permission under /usr/local. If /usr/local/bin is NFS-mounted, then it is possible to wipe out the server's copy of this directory from a client when root permissions are extended over the network. One clear-cut case where root permissions should be extended on an NFS filesystem is for the root and swap partitions of a diskless client, where they are mandatory. One other possible scenario in which root permissions are useful is for cross-server mounted filesystems. Assuming that only the system administration staff is given superuser privileges on the file servers, extending these permissions across NFS mounts may make software distribution and maintenance a little easier. Again, the pitfalls await, but hopefully the community with networked root permissions is small and experienced enough to use these sharp instruments safely. On the client side, you may want to protect the NFS client from foreign setuid executables of unknown origin. NFS-mounted setuid executables should not be trusted unless you control superuser access to the server from which they are mounted. If security on the NFS server is compromised, it's possible for the attacker to create setuid executables which will be found -- and executed -- by users who NFS mount the filesystem. The setuid process will have root permission on the host on which it is running, which means it can damage files on the local host. Execution of NFS-mounted setuid executables can be disabled with the nosuid mount option. This option may be specified as a suboption to the -o command-line flag, the automounter map entry, or in the /etc/vfstab entry:share -o rw,root=bitatron:corvette /export/home/work
A bonus is that on many systems, such as Solaris, the nosuid option also disables access to block and character device nodes (if not, check your system's documentation for a nodev option). NFS is a file access protocol and it doesn't allow remote device access. However it allows device nodes to be stored on file servers, and they are interpreted by the NFS client's operating system. So here is another problem with mounting without nosuid. Suppose under your NFS client's /dev directory you have a device node with permissions restricted to root or a select group of users. The device node might be protecting a sensitive resource, like an unmounted disk partition containing, say, personal information of every employee. Let's say the major device number is 100, and the minor is 0. If you mount an NFS filesystem without nosuid, and if that filesystem has a device node with wide open permissions, a major number of 100, and a minor number of 0, then there is nothing stopping unauthorized users from using the remote device node to access your sensitive local device. The only clear-cut case where NFS filesystems should be mounted without the nosuid option is when the filesystem is a root partition of a diskless client. Here you have no choice, since diskless operation requires setuid execution and device access. We've discussed problems with setuid and device nodes from the NFS client's perspective. There is also a server perspective. Solaris and other NFS server implementations have a nosuid option that applies to the exported filesystem:automounter auto_local entry: bin -ro,nosuid toolbox:/usr/local/bin vfstab entry: toolbox:/usr/local/bin - /usr/local/bin nfs - no ro,nosuid
This option is highly recommended. Otherwise, malicious or careless users on your NFS clients could create setuid executables and device nodes that would allow a careless or cooperating user logged into the server to commit a security breach, such as gaining superuser access. Once again, the only clear-cut case where NFS filesystems should be exported without the nosuid (and nodev if your system supports it, and decouples nosuid from nodev semantics) option is when the filesystem is a root partition of a diskless client, because there is no choice if diskless operation is desired. You should ensure that any users logged into the diskless NFS server can't access the root partitions, lest the superuser on the diskless client is careless. Let's say the root partitions are all under /export/root. Then you should change the permissions of directory /export/root so that no one but superuser can access:share -o rw,nosuid /export/home/stuff
# chown root /export/root # chmod 700 /export/root
This says to export the filesystem, permitting AUTH_SYS credentials. However if a user's NFS request comes in with invalid credentials or non-AUTH_SYS security, treat and accept the user as anonymous. You can also map all users to anonymous, whether they have valid credentials or not:share -o sec=sys:none,rw /export/home/engin
By default, the anonymous user is nobody, so unknown users (making the credential-less requests) and superuser can access only files with world permissions set. The anon export option allows a server to change the mapping of anonymous requests. By setting the anonymous user ID in /etc/dfs/dfstab, the unknown user in an anonymous request is mapped to a well-known local user:share -o sec=none,rw /export/home/engin
In this example, any request that arrives without user credentials will be executed with UID 100. If /export/home/engin is owned by UID 100, this ensures that unknown users can access the directory once it is mounted. The user ID mapping does not affect the real or effective user ID of the process accessing the NFS-mounted file. The anonymous user mapping just changes the user credentials used by the NFS server for determining file access permissions. The anonymous user mapping is valid only for the filesystem that is exported with the anon option. It is possible to set up different mappings for each filesystem exported by specifying a different anonymous user ID value in each line of the /etc/dfs/dfstab file:share -o rw,anon=100 /export/home/engin
Anonymous users should almost never be mapped to root, as this would grant superuser access to filesystems to any user without a valid password file entry on the server. An exception would be when you are exporting read-only, and the data is not sensitive. One application of this is exporting directories containing the operating system installation. Since operating systems like Solaris are often installed over the network, and superuser on the client drives the installation, it would be tedious to list every possible client that you want to install the operating system on. Anonymous users should be thought of as transient or even unwanted users, and should be given as few file access permissions as possible. RPC calls with missing UIDs in the credential structures are rejected out of hand on the server if the server exports its filesystems with anon=-1. Rather than mapping anonymous users to nobody, filesystems that specify anon=-1 return authentication errors for RPC calls with no credentials in them. Normally, with the anonymous user mapped to nobody, anonymous requests are accepted but have few, if any, permissions to access files on the server. Mapping unknown users is a risky venture. Requests that are missing UIDs in their credentials may be appearing from outside the local network, or they may originate from machines on which security has been compromised. Thus, if you must export filesystems with the anonymous user mapped to a UID other than nobody, you should limit it to a smaller set of hosts:share -o rw,anon=100 /export/home/engin share -o rw,anon=200 /export/home/admin share -o rw,anon=300 /export/home/marketing
We discuss limiting exports to certain hosts in the next section.share -o rw=engineering,anon=100 /export/home/engin # a nergroup share -o rw=admin1:admin2,anon=200 /export/home/admin # a pair of hosts share -o rw=.marketing.widget.com,anon=300 /export/home/marketing # a domain
This specification is typical of that for the root filesystem of a diskless client. The client machine is given root access to the filesystem, and access is further restricted to host noreast only. No user can look at noreast 's root filesystem unless he or she can log into noreast and look locally. The hosts listed in a rw= list can be individual hostnames or netgroup names, separated by colons. On Solaris 8, the hosts can also be DNS domain names, if prefixed by a leading dot (.), or a network number if preceded by a leading at sign (@). Solaris 8 also has the capability to deny specific hosts (individual hostnames, netgroups, domains, or network numbers) access. For example:share -o rw=noreast,root=noreast /export/root/noreast
Restricting host access ensures that NFS is not used to circumvent login restrictions. If a user cannot log into a host to restrict access to one or more filesystems, the user should not be able to recreate that host's environment by mounting all of its NFS-mounted filesystems on another system.share -o rw=-marketing /source
In this example, the machines in system-engineering netgroup are authorized to only browse the source code; they get read-only access. Of course, this prevents users on machines authorized to modify the source from doing their job. So you might instead use:share -o ro=system-engineering /source
In this example, the machines in source-group are authorized to modify the source code get read and write access, whereas the machines in the system-engineering netgroup, which are authorized to only browse the source code, get read-only access.share -o rw=source-group,ro=system-engineering /source
In addition, if you don't want to reboot your server for this to take effect, then, you can change it on the fly by doing:set nfssrv:nfs_portmon = 1
This script sets the value of nfs_ portmon to 1 in the kernel's memory image, enabling port monitoring. Any request that is received from a nonprivileged port is rejected. By default, some mountd daemons perform port checking, to be sure that mount requests are coming from processes running with root privileges. It rejects requests that are received from nonprivileged ports. To turn off port monitoring in the mount daemon, add the -n flag to its invocation in the boot script:echo "nfs_portmon/W1" | adb -k -w
Not all NFS clients send requests from privileged ports; in particular, some PC implementations of the NFS client code will not work with port monitoring enabled. In addition, some older NFS implementations on Unix workstations use nonprivileged ports and require port monitoring to be disabled. This is one reason why, by default, the Solaris 8 nfs_ portmon tunable is set to zero. Another reason is that on operating systems like Windows, with no concept of privileged users, anyone can write a program that binds to a port less than 1024. The Solaris 8 mountd also does not monitor ports, nor is there any way to turn on mount request port monitoring. The reason is that as of Solaris 2.6 and onward, each NFS request is checked against the rw=, ro=, and root= lists. With that much checking, filehandles given out a mount time are longer magic keys granting access to an exported filesystem as they were in previous versions of Solaris and in other, current and past, NFS server implementations. Check your system's documentation and boot scripts to determine under what conditions, if any, port monitoring is enabled.mountd -n
The proto=tcp option forces the mount to use the TCP/IP protocol. Firewalls prefer to deal with TCP because it establishes state that the firewall can use to know if a TCP segment from the outside is a response from an external server, or a call from an external client. The former is not usually deemed risky, whereas the latter usually is. The public option does the following:mount commmand: mount -o proto=tcp,public nfs.eisler.com:/export/home/mre /mre automounter auto_home entry: mre -proto=tcp,public nfs.eisler.com:/export/home/& vfstab entry: nfs.eisler.com:/export/home/mre - /mre nfs - no proto=tcp,public
To understand what setfacl did, let's read back the ACL for blockhead:% chmod 0600 blockhead % setfacl -m mask:rw-,user:linus:rw-,user:sally:rw- blockhead
The user: entries for sally and linus correspond to the rw permissions lucy requested. The user:: entry simply points out that the owner of the file, lucy has rw permissions. The group:: entry simply says that the group owner, peanuts, has no access. The mask: entry says what the maximum permissions are for any users (other than the file owner) and groups. If lucy had not included mask permissions in the setfacl command, then linus and sally would be denied access. The getfacl command would instead have shown:% getfacl blockhead # file: blockhead # owner: lucy # group: peanuts user::rw- user:linus:rw- #effective:rw- user:sally:rw- #effective:rw- group::--- #effective:--- mask:rw- other:---
Note the difference from the two sets of getfacl output: the effective permissions granted to linus and sally. Once you have the ACL on a file the way you want it, you can take the output of getfacl on one file and apply it to another file:% getfacl blockhead # file: blockhead # owner: lucy # group: peanuts user::rw- user:linus:rw- #effective:--- user:sally:rw- #effective:--- group::--- #effective:--- mask:--- other:---
It would be hard to disagree if you think this is a pretty arcane way to accomplish something that should be fairly simple. Nonetheless, ACLs can be leveraged to solve the "too many groups" problem described earlier in this chapter in Section 12.4.1, "RPC security". Rather than put users into lots of groups, you can put lots of users into ACLs. The previous example showed how to copy an ACL from one file to another. You can also set a default ACL on a directory, such that any files or directories created under the top-level directory are inherited. Any files or directories created in a subdirectory inherit the default ACL. It is easier to hand edit a file containing the ACL description than to create one on the command line. User lucy creates the following file:% touch patty % getfacl blockhead | setfacl -f /dev/stdin patty % getfacl patty # file: patty # owner: lucy # group: peanuts user::rw- user:linus:rw- #effective:rw- user:sally:rw- #effective:rw- group::--- #effective:--- mask:rw- other:---
It is the default: entries that result in inherited ACLs. The reason why we add execution permissions is so that directories have search permissions, i.e., so lucy and her cohorts can change their current working directories to her protected directories. Once you've got default ACLs set up for various groups of users, you then apply it to each top-level directory that you create:user::rwx user:linus:rwx user:sally:rwx group::--- mask:rwx other:--- default:user::rwx default:user:linus:rwx default:user:sally:rwx default:group::--- default:mask:rwx default:other:---
Note that you cannot apply an ACL file with default: entries in it to nondirectories. You'll have to create another file without the default: entries to use setfacl -f on nondirectories:% mkdir lucystuff % setfacl -f /home/lucy/acl.default lucystuff
The preceding example strips out the default: entries. However it leaves the executable bit on in the entries:% grep -v '^default:' | /home/lucy/acl.default > /home/lucy/acl.files
This might not be desirable for setting an ACL on existing regular files that don't have the executable bit. So we create a third ACL file:% cat /home/lucy/acl.files user::rwx user:linus:rwx user:sally:rwx group::--- mask:rwx other:---
This first turns off every execute permission bit, but then sets the mask to allow execute permission should we later decide to enable execute permission on a file:% sed 's/x$/-/' /home/lucy/acl.files | sed 's/^mask.*$/mask:rwx/' \ > /home/lucy/acl.noxfiles
With an ACL file with default: entries, and the two ACL files without default: entries, lucy can add protection to existing trees of files. In the following example, oldstuff is an existing directory containing a hierarchy of files and subdirectories:% cat /home/lucy/acl.noxfiles user::rw- user:linus:rw- user:sally:rw- group::--- mask:rwx other:---
In addition to solving the "too many groups in NFS" problem, another advantage of ACLs versus groups is potential decentralization. As the system administrator, you are called on constantly to add groups, or to modify existing groups (add or delete users from groups). With ACLs, users can effectively administer their own groups. It is a shame that constructing ACLs is so arcane, because it effectively eliminates a way to decentralize a security access control for logical groups of users. You might want to create template ACL files and scripts for setting them to make it easier for your users to use them as a way to wean them off of groups. If you succeed, you'll reduce your workload and deal with fewer issues of "too many groups in NFS."fix the directories: % find oldstuff -type d -exec setfacl -f /home/lucy/acl.default {} \; fix the nonexecutable files: % find oldstuff ! -type d ! ( -perm -u=x -o -perm -g=x -o -perm -o=x ) \ -exec setfacl -f /home/lucy/acl.noxfiles {} \; fix the executable files: % find oldstuff ! -type d ( -perm -u=x -o -perm -g=x -o -perm -o=x ) \ -exec setfacl -f /home/lucy/acl.noxfiles {} \;
TIP: In Solaris, ACLs are not preserved when copying a file from the local ufs filesystem to a file in the tmpfs (/tmp) filesystem. This can be a problem if you later copy the file back from /tmp to a ufs filesystem. Also, in Solaris, ACLs are not, by default, preserved when generating tar or cpio archives. You need to use the -p option to tar to preserve ACLs when creating and restoring a tar archive. You need to use the -P option to cpio when creating and restoring cpio archives. Be aware that non-Solaris systems probably will not be able to read archives with ACLs in them.
No matter what the group ownership of blockhead is, and no matter what the other permissions on blockhead are, charlie will not be able read or write the file.% setfacl -m user:charlie:--- blockhead
[21]A similar security issue occurs when the superuser accesses a file owned by a user with permissions 0600. If the superuser is mapped to nobody on the server, then the superuser shouldn't be allowed to access the file. But if the file is cached, the superuser can read it. This is an issue only with NFS Version 2, not Version 3.This is not the case for the NFS Version 3 server though. With the NFS Version 3 protocol, there is an ACCESS operation that the client sends to the server to see if the indicated user has access to the file. Thus the exact, unmapped permissions are rendered back to the NFS Version 3 client. We said that the Solaris NFS server will report to most NFS Version 2 clients permissions of 0600. However, starting with Solaris 2.5 and higher, a side band protocol to NFS was added, such that if the protocol exists, the client can not only get the exact permissions, but also use the sideband protocol's ACCESS procedure for allowing the server to permissions the access checks. This then prevents charlie or the superuser from gaining unauthorized access to files. What if you have NFS clients that are not running Solaris 2.5 or higher, or are not running Solaris at all? In that situation you have two choices: live with the fact that some users will be denied access due to the minimal permissions behavior, or you can use the aclok option of the Solaris share command to allow maximal access. If the filesystem is shared with aclok, then if anyone has read access to the files, then everyone does. So, charlie would then be allowed to access file blockhead. Another issue with NFS and ACLs is that the NFS protocol has no way to set or retrieve ACLs, i.e., there is no protocol support for the setfacl or getfacl command. Once again, the sideband protocol in Solaris 2.5 and higher comes to the rescue. The sideband protocol allows ACLs to be set and retrieved, so setfacl and getfacl work across NFS.
TIP: IBM's AIX and Compaq's Tru64 Unix have sideband ACL protocols for manipulating ACLs over NFS. Unfortunately, none of the three protocols are compatible with each other.
12.3. Password and NIS security | 12.5. Stronger security for NFS |
Copyright © 2002 O'Reilly & Associates. All rights reserved.