One of the most confusing issues for novice users of Solaris is understanding the Solaris file access permissions system. The basic approach to setting and interpreting relative file permissions is using a set of symbolic codes to represent users and permission types. However, even advanced users may find it difficult to understand the octal permissions codes that are used to set absolute permissions.
When combined with a default permission mask set in the user’s shell (the umask), octal permission codes are more powerful than symbolic permission codes.
The Solaris file system permits three basic kinds of file access—the ability to read (r), to write (w), and to execute (x) a file or directory. These permissions can be granted exclusively or nonexclusively on individual files, or on a group of files specified by a wildcard (*). These permissions can be set by using the chmod command, in combination with a + operator. Permissions can be easily removed with the chmod command by using the - operator.
For example, to set read permissions (for the current user) on the file /usr/local/lib/libproxy.a, you would use this command:
$ chmod +r /usr/local/lib/libproxy.a
Or, to set read permissions for all users on the file /usr/local/lib/libproxy.a, you would use this command:
$ chmod a+r /usr/local/lib/libproxy.a
To remove read permissions on the file /usr/local/lib/libproxy.a for all users who are not members of the current user’s default group, you would use this command:
$ chmod o-r /usr/local/lib/libproxy.a
This does not remove the group and user read permissions that were set previously. Similarly, you can set execute and write permissions. For example, to set execute permissions on the /usr/local/bin/gcc files for each class of user (current user, group, and world), you would use the commands:
$ chmod u+x /usr/local/bin/gcc $ chmod g+x /usr/local/bin/gcc $ chmod o+x /usr/local/bin/gcc
To explicitly remove write permissions on the /usr/local/bin/gcc files for each class of user (current user, group, and world), you would use the commands
$ chmod u-w /usr/local/bin/gcc $ chmod g-w /usr/local/bin/gcc $ chmod o-w /usr/local/bin/gcc
It makes sense to combine these settings into a single command:
$ chmod oug-w /usr/local/bin/gcc
The rationale behind using read and write permissions should be clear: permitting read access on a file allows an identified user to access the text of a file by reading it byte by byte; write access permits the user to modify or delete any file on which the write permission is granted, regardless of who originally created the file. Thus, individual users can create files that are readable and writable by any other user on the system.
The permission to execute a file must be granted on scripts (such as shell scripts or Perl scripts) in order for them to be executed. Compiled and linked applications must also have the execute bit set on a specific application.
The executable permission must also be granted on the special files that represent directories on the file system, if the directory’s contents are to be accessed by a specific class of user.
The different options available for granting file access permissions can sometimes lead to interesting but confusing scenarios: For example, permissions can be set to allow a group to delete a file but not to execute it. More usefully, a group might be given execute permission on an application but be unable to write over it. In addition, setting file permissions using relative permission strings (rather than absolute octal permission codes) means that permissions set by a previous change of permission command (chmod) are not revoked by any subsequent chmod commands.
However, the permissions themselves are only half the story. Unlike single-user file systems, permissions on Solaris are associated with different file owners (all files and processes on a Solaris system are “owned” by a specific user). In addition, groups of users can be granted read, write, and execute permissions on a file or set of files stored in a directory. Or, file permissions can be granted on a system-wide basis, effectively granting file access without respect to file ownership. Because file systems can be exported using NFS and/or Samba, it’s bad practice to grant system-wide read, write, and execute permissions on any file unless every user needs access to that file. For example, all users need to read the password database (/etc/passwd), but only the root user should have read access to the shadow password database (/etc/shadow).
Blindly exporting all files with world read, write, or execute permissions on an NFS-shared volume is inviting trouble.
The three file system categories of ownership are defined by three permission setting categories: the user (u), who owns the file; group members (g), who have access to the file; and all other users (o) on the system. The group specified by g can be the user’s primary group (as defined in /etc/passwd), or a secondary group to which the file has been assigned (defined in /etc/group). Remember that there are ultimately few secrets on a Solaris file system: The root user has full access at all times (read, write, and execute) on all files on the file system, even if a user removes all permissions on a file, the rule of root is absolute. If the contents of a file really need to be hidden, encrypting a file’s contents using PGP, crypt, or a similar product is best. A root user can also change the ownership of a file—thus, a user’s files do not absolutely belong to a specific user. The chown command can be used only by the superuser for this purpose.
Policies regarding default file permissions need to be set selectively in different environments. For example, in a production web server system that processes credit card data, access should be denied by default to all users except those required to conduct online transactions (for example, the “apache” user for the Apache web server). On a system that supports team-based development, permissions will obviously need to be set that allow the exchange of data between team partners, but that prevent the access to development files by others.
Very few Solaris systems would allow a default world-writable policy on any file system, except for the temporary swap (/tmp) file system.
Enforcing system-wide permissions is possible by using a default umask, which sets the read, write, and execute permissions on all new files created by a specific user. If a user wishes to use a umask other than the default system-wide setting, he or she can achieve this by setting it on the command line when required, or in the user’s shell startup file (for example, .kshrc for Korn shell).
We start our examination of Solaris file permissions by examining how to create files, set permissions, and change ownerships and group memberships, and how to use the ls command to examine existing file permissions. All of these commands can be used by nonprivileged users, except for the chown command.
The ls command is the main directory and file permission listing program used in Solaris. When displaying a long listing, it prints file access permissions, user and group ownerships, file size and creation date, and the filename. For example, for the password file /etc/passwd, the output from ls would look like this:
$ ls –l /etc/passwd -r--r--r-- 1 root other 256 Sep 18 00:40 passwd
This directory entry can be read from left to right in the following way:
The password file is not a directory, indicated by the first “-”. This could also indicate a character or block special device
The password file has read-only permissions for the owner r-- (but not execute or write permissions).
The password file has read-only permissions for group members r--.
The password file has read-only permissions for other staff r--.
The password file is owned by the root user.
The password file has group other permissions.
The password file size is 256 kilobytes.
The password file was created on September 18th, at 00:40 A.M.
The name of the password file is passwd.
The permissions string shown changes depending on the permissions that have been set by the owner. For example, if the password file had execute and write permissions for the root user, the permissions string would read –rwxr--r--, rather than just –r--r--r--. Each of the permissions can be set using symbolic or octal permissions codes, by using the chmod command.
Except the GID setting on a directory, which must be set using chmod g+s dirname, everything else can be set using octal codes.
You’ve seen how a normal file looks under ls, but let’s compare this with a directory entry, which is a special kind of file that is usually created by the mkdir command:
# mkdir samples
You can check the permissions of the directory entry by using the ls command:
# ls -l total 8 drwxrwxr-x 2 root other 512 Sep 5 13:41 samples
The directory entry for the directory samples can be read from left to right in the following way:
The directory entry is a special file denoted by a leading d.
The directory entry has read, write, and execute permissions for the owner rwx.
The directory entry has read, write, and execute permissions for group members rwx.
The directory entry has read and execute permissions for other staff r-x.
The directory entry is owned by the root user.
The directory entry has other group permissions.
The directory entry size is 512 kilobytes.
The directory entry was created on September 5th of the current year, at 1:41 P.M.
The name of the directory is samples.
For a directory to be accessible to a particular class of user, the executable bit must be set using the chmod command.
You must be able to identify every element of a file permissions string.
Some expert users prefer not to separate user and permission information by using the user symbols (o, u, g) and the permission symbols (r, w, x). Instead, a numeric code can be used to combine both user and permission information. If you use a lot of common permissions settings, it may be easier for you to remember a single octal code than to work out the permissions string symbolically. The octal code consists of three numbers, which represent owner permissions, group permissions, and other user permissions, respectively (from left to right). The higher the number, the greater the permissions for each user. For example, to set a file to have read, write, and execute permissions for the file owner, you can use the octal code 700 with the chmod command:
$ chmod 700 *
You can now check to see if the correct permissions have been granted:
$ ls -l total 4 drwx------ 2 root users 4096 Jun 8 20:10 test -rwx------ 1 root users 0 Jun 8 20:10 test.txt
You can also grant read, write, and execute permissions to members of the group users by changing the middle number from 0 to 7:
$ chmod 770 *
Again, the changes are reflected in the symbolic permissions string displayed by ls:
$ ls -l total 4 drwxrwx--- 2 root users 4096 Jun 8 20:10 test -rwxrwx--- 1 root users 0 Jun 8 20:10 test.txt
If you want to grant read, write, and execute permissions to all users, simply change the third permissions number from 0 to 7:
$ chmod 777 *
Now, all users on the system have read, write, and execute permissions on all files in the directory:
$ ls -l total 4 drwxrwxrwx 2 root users 4096 Jun 8 20:10 test -rwxrwxrwx 1 root users 0 Jun 8 20:10 test.txt
Of course, the codes that can be used to specify permissions are usually not just 0 or 7. For example, the code 5 gives read and execute access, but not write access. So, if you wanted to grant read and execute access to members of the group, but deny write access, you could use the code 750:
$ chmod 750 *
This produces the following result:
$ ls -l total 4 drwxr-x--- 2 root users 4096 Jun 8 20:10 test -rwxr-x--- 1 root users 0 Jun 8 20:10 test.txt
If you wanted to remove all access permissions from the files in the current directory, you could use the code 000 (you should not normally need to do this):
$ chmod 000 *
Let’s examine the result of the command:
$ ls -l total 4 d--------- 2 root users 4096 Jun 8 20:10 test ---------- 1 root users 0 Jun 8 20:10 test.txt
All access permissions have been removed, except for the directory indicator on the special file test. Note the main difference between setting files using symbolic codes rather than octal codes: Symbolic codes are relative, numeric codes are absolute. This means that unless you explicitly revoke a file permission when setting another using symbolic codes, it will persist. Thus, if a file already has group write access, and you grant group execute access (or remove group execute access), the write access permission is not removed. However, if you specify only group execute access using an octal code, the group write access will automatically be removed if it has been previously set.
You may well find that in startup scripts and situations where the permissions are unknown in advance, using octal codes is safer.
You must be able to interpret every element of an octal permissions code.
You can enforce system-wide permissions by using a default “user mask” (umask), which sets the read, write, and execute permissions on all new files created by a specific user. If a user wants to use a umask other than the default system-wide setting, he or she can achieve this by setting it on the command line when required, or in the user’s shell startup file (for example, .kshrc for Korn shell), or in the global system default file /etc/default/login. In addition, the mask that is set for the current user can be displayed by using the umask command by itself.
Like file permissions, the umask is set using octal codes (symbolic codes cannot be used). There are two different strategies for computing umasks. For directories, you must subtract the octal value of the default permission you want to set from octal 777. For files, you must subtract the octal value of the default permission you want to set from octal 666. For example, to set the default permission to 444 (all read-only), you would subtract 444 from 666 for files, to derive the umask of 222. For the default permission 600 (user read/write, no other access), you would subtract 600 from 666, leaving a umask of 066 (which will often be displayed as 66).
If you want all users to have full access permissions on all files that you create, you would set the umask to 000 (666-000=666):
$ umask 000
Let’s examine the results, after creating a file called data.txt and after setting the umask to 000:
$ touch data.txt $ ls -l total 4 -rw-rw-rw- 1 root users 0 Jun 8 20:20 data.txt
Everyone now has full access permissions. However, you are more likely to set a umask like 022, which would give new files the permissions 755 (777 – 022=755). This would give the file owner read, write, and execute access, but only read permissions for group members and other users:
$ umask 022
If you now create a new file called newdata.txt with the new umask, you should see that the default permissions have changed:
$ touch newtest.txt $ ls -l total 4 -rw-r--r-- 1 root root 0 Jun 8 20:21 newdata.txt -rw-rw-rw- 1 root users 0 Jun 8 20:20 data.txt
If you’re more conservative, and you don’t want to grant any access permissions to other users (including group members), you can set the umask to 077, which still gives the file owner full access permissions:
bash-2.03$ umask 077
Let’s see what happens when you create a new file called lastminute.txt:
bash-2.03$ touch lastminute.txt bash-2.03$ ls -l total 4 -rw-r--r-- 1 root root 0 Jun 8 20:21 newdata.txt -rw------- 1 root root 0 Jun 8 20:22 lastminute.txt -rw-rw-rw- 1 root users 0 Jun 8 20:20 data.txt
The new file has full access permissions for the owner, but no access permissions for other users. Resetting the umask does not affect the permissions of other files that have already been created.
It is interesting that you can also get umask to print the symbolic codes using umask –S—this is the actual binary, not the shell built-in, though.
The file permissions we’ve covered so far are used by users in their day-to-day file management strategies. However, administrators can make use of a different set of file permissions, which allow files to be executed as a particular user (setuid), and/or as a member of a particular group (setgid). These facilities are very powerful, because they allow unprivileged users to gain access to limited superuser privileges in many cases, without requiring superuser authentication. For example, the volume daemon (vold) allows unprivileged users logged into the console to mount and unmount CD-ROMs and floppy disks, an operation which required superuser privileges in previous Solaris releases. Here, the effective user ID is set to 0, meaning that unprivileged users can effectively run processes as root.
The downside to this is obvious: setgid and setuid permissions open up a Pandora’s box in terms of security, because normal authentication procedures are bypassed. For example, imagine a device management tool that needed to run as setuid 0 in order to read and write device files. If the tool had a standard feature of many UNIX programs (the ability to spawn a shell), the shell spawned would have full root privileges, rather than the privileges of the original user. For this reason, some administrators refuse to allow setgid and setuid permissions to be set.
The find command can be used to scan all file systems and automatically remove any files with setuid or setgid privileges.
You can determine whether a file is setuid by root by (a) checking for files that are owned by root and (b) checking whether these files have the s flag assigned to the user’s permissions. For example, if a file management tool called filetool was setuid root, the following directory listing would clearly indicate this property:
-r-sr-sr-x 3 root sys 1220334 Jul 18 11:01 /usr/local/bin/filetool
The first s in the permissions table refers to setuid root. In addition, this file is also setgid for the sys group, which is indicated by the second s in the permissions table.
The setuid bit can be set by using a command like this
# chmod u+s file.txt
where file.txt is the file that requires setuid to be set. The setgid bit can be set by using a command like this
# chmod g+s file.txt
where file.txt is the file that requires setgid to be set.
A network administrator once explained to me that sticky bits were those bits that slowed down network transmission rates, because they were highly attracted to magnetic qualities of the Ethernet. This is not true! A sticky bit is a special permission that prevents files in common file areas from being deleted by other users. For example, a download area consisting of a large 10GB partition may be set aside for user downloads, which are not counted against individual user quotas. This means that users could download up to 10GB of data without infringing on their allocated directory space. However, although a shared public file area sounds like a great idea, it would be unwise to allow users to overwrite one another’s files. In this case, the sticky bit can be set on the top-level directory of the public file area, allowing only users who created individual files to delete them.
You can set the sticky bit by using a command like this:
# chmod +t somedir
where somedir is the directory that requires the sticky bit to be set. You could also use the 1755 for octal.
One problem with assigning file access permissions is that users other than one’s self fall into two categories: group members or nongroup members. Thus, if you want to make some files available to one group of users and not another, you will need to ask the system administrator to create a group for you. Of course, the main problem with the random group creation approach is group sprawl—administrators are generally unwilling to create groups at the request of users because of the overhead in administering potentially hundreds of different groups on each system, and the number of groups that one user can be in is limited.
The best solution to the problem is to leave group members to reflect organizational divisions, and to use access control lists (ACLs) to manage file access. While it may seem like creating more work to have two sets of file access permissions operating, in reality it’s the simplest solution for users that doesn’t require superuser permission.
To grant the user charles read-only access to the file secret.doc, which is owned by the user ainsley and has read-write permissions only for ainsley, the following command would be executed by ainsley:
$ setfacl -m user:charles:r-- secret.doc
Alternatively, to allow charles to have read-write access to the file, the following command can be used:
$ setfacl -m user:charles:rw- secret.doc
When an ACL has been set, the file listing shows a + symbol at the end of the permissions string:
# ls -l /home/charles/secret.doc -rw-------+ 1 charles admin 105433 Jan 24 12:07 /home/charles/secret.doc
The getfacl command can be used to display the ACLs for any file on the file system, displaying the real and effective access permissions on files as determined by file permissions and ACLs.
The output of getfacl for a file (/etc/passwd in this example) looks like this:
$ getfacl /etc/passwd # file: /etc/passwd # owner: root # group: sys user::rw- group::r-- #effective:r-- mask:r-- other:r--