Advanced use of Permissions and ACLs


Copyright 2002, 2003 Andy Barclay
OpenContent License (OPL)

Advanced file permissions
-------------------------
setuid, setgid
---------------

When you want to change your password, you use the command "passwd".
This program reads input from the keyboard, encrypts it, then stores
the encrypted password in the file /etc/shadow.

If you look at the permissions on /etc/shadow, you will find that the
file is not readable, let alone writeable, by you, the non-priviliged
user.

-r--------   1 root     sys          480 Jul  3 12:21 /etc/shadow

How then, is the passwd program, when run by the non-priviliged user,
able to update this file?

If you look at the permissions on the /bin/passwd program you will find
an interesting set:

-r-sr-sr-x   3 root     sys        87536 Jan  5  2000 /bin/passwd

Notice the "s" where the owner's execute permission normally is stored.
This is known as setuid permission, and it means that when the /bin/passwd
program is run, it executes as the owner of the file, in this case root, 
rather than as the user who actually types the command.

So its really root that is attempting to update the shadow file, and
of course root can write to any file, so the passwd change works.

Notice also the "s" in the spot where the group execute permission indication
is normally stored.
Similar to the setuid, this is known as setgid. When this bit is set, it
 means that when the program executes, it does so with the
group of file, not as the primary group of the user running the program.

An excellent example of this is the /bin/mail program.
Received mail for the user fred is stored in /var/mail/fred
Since, fred probably don't want other people on the system to be able to read
his mail, the permissions on the file are:

-rw-rw----   1 fred      mail         600 Jul  3 13:33 fred

Unfortunately, even though fred doesn't want anyone to read his mail,
he still wants people to be able to send him mail.

Now, when andy runs the command "mail fred", this program has to
be able to modify the file /var/mail/fred.

Look at the permissions of the /bin/mail program:"

-r-x--s--x   1 root     mail       62800 Jan  5  2000 /bin/mail

When /bin/mail is executed by some user on the system, the program runs in
group "mail" which DOES have write permission the the file.

sticky bit
----------

Recall from our discussion of simple permissions that a user can remove
a file, if that user has write permission to the directory containing the
file, regardless of the user's access rights to the file itself.

Example
	drwxrwxrwx  32 abarclay staff       1536 Aug  3 22:14 /home/abarclay
	-rw-------   1 abarclay staff       2551 May 31 05:39 /home/abarclay/.profile

With the permissions shown above, the user bill could easily remove the
file /home/abarclay/.profile

Consider the purpose of the /tmp directory. It's purpose is to provide
space where user's can write files that are of a transient nature.
Who needs to be able to write files into this directory? - Everyone
So what should the permissions on this directory be? - 777

With 777 permissions, should fred create a file in /tmp, anyone could
remove it!

Obviously this is unacceptable. The solution was to overload an already
existing permission bit called the "sticky bit".
When set on an executable program, the sticky bit caused the "text" of the
program (thats the code part) to remain resident in memory, so that it
could be re-used the next time the program needed to be run.
(This bit is seldomly used for this purpose anymore).

Since the sticky bit had no implied meaning with respect to a directory,
it was decided to make its meaning thus:

When the sticky bit is set on a directory, the only people who can remove
files from that directory are:
1) root
2) the owner of the directory
3) the owner of the file to be removed

So, the permissions on the /tmp directory are actually:

drwxrwxrwt   7 sys      sys          463 Aug  3 22:20 /tmp

The "t" represents the sticky bit.

Usage
------
How do we apply the setuid, setgid, or sticky bit to a file or directory?

Using symbolic notation, we can do it like this:

{set the setuid bit on the file bin/foo}
$ chmod u+s bin/foo

{set the setgid bit on the file bin/bar}
$ chmod g+s bin/bar

{set the sticky bit on the directory "testing"}
$ chmod o+t testing

Can we set these bits using octal permissions?

Sure. Even though the "ls -l" output shows us 9 bits of permissions, the 
inode actually stores 12 bits. Even though the display embeds the setuid, 
setgid, and sticky bits within the same 9 characters, they are actually
the most significant bits of the permissions and as such, can be represented
by an additional octal digit when using chmod.

Example
-------

To set the permissions on the tmp directory.
# chmod 1777 /tmp

To set the permissions on the /bin/passwd file
# chmod 6555 /bin/passwd

To set the permissions on the /bin/mail file
# chmod 2555 /bin/mail


Really wacky stuff
-------------------

setgid on a directory
---------------------
	Assume that user bill is in the "eng" group and user "mary" is in the
"acct" group.
The engineers very seldom talk to accounting except periodically, bill
has to write up a budget and have it checked by accounting. It may
have to go through a series of changes and reviews.

One way to accomplish this would be for bill to write the file, then
change the permissions on it so that people in the group "acct" can
read and write to the file. This would work, but its a pain.

The better solution, is to create a shared area, say called /budget.
Create a new unix group called "budget" and make sure /budget has this
as its group. Finally, use chmod to make the directory setgid.

When setgid is set on a directory, any files created in that directory
automatically get the group of the directory instead of the creating
user's primary group.

Example
-------
$ ls -ld /tmp /budget
drwxr-sr-x   2 abarclay bin          512 Aug  3 22:56 /budget
drwxrwxrwt   7 sys      sys          463 Aug  3 22:20 /tmp

$ touch /tmp/junk /budget/junk
$ ls -ld /tmp/junk /budget/junk
-rw-r--r--   1 abarclay bin            0 Aug  3 22:59 /budget/junk
-rw-r--r--   1 abarclay staff          0 Aug  3 22:59 /tmp/junk

Notice that the file created in /budget is in group "bin", even though
the user "abarclay" doesn't even belong to the group "bin"!

$ groups
staff sysadmin

*************************************************************

Really, really wacky stuff
--------------------------

Access Control Lists (ACLs)
---------------------------

I am not sure who thought of the concept of ACLs first, but it was
definately made famous by Novell.

The Unix permissions strategy, although elegant, is limited.

What is I want to give Mary, Paul, and John access to a file, and yet
they are not all members of a particular group?
I would have to create a group with just them as members then ensure
that the files that I want them to share are in the new group.

Access control lists allow us to give/restrict access to individual users
and groups.

Lets say that for some strange reason, we wanted to give the user "abarclay"
read access to the /etc/shadow file (this is not likely - but lets just
assume).

We can use the setfacl command to grant this access.

$ ls -l /etc/shadow
-r--------   1 root     sys          480 Jul  3 12:21 /etc/shadow

# setfacl -m user:abarclay:r-- /etc/shadow

$ ls -l /etc/shadow
-r--------+  1 root     sys          480 Jul  3 12:21 /etc/shadow

Notice the "+" symbol at the end of the permissions. This tells us that
this file has ACLs associated with it.

We can examine the ACLs by using the getfacl command:
# getfacl /etc/shadow

# file: /etc/shadow
# owner: root
# group: sys
user::r--
user:abarclay:r--               #effective:---
group::---              #effective:---
mask:---
other:---


Unfortunately ACLs are seldom used in Solaris. This may be because
the resulting access is very counter-intuitive.

Notice that there are comments in the output of getfacl that indicate
that even though abarclay supposedly has read access to the file now,
the "effective" access for abarclay is "---".

Logging in as abarclay and trying to view the file confirms that this
is the case:

quake:/home/abarclay$ cat /etc/shadow
cat: cannot open /etc/shadow

Why is this?

The value of the "mask" setting is limiting the maximum permissions available
though ACL.  The "mask" value, although similar in name, does not work at all
like the umask does for permissions. 

In this case, the mask shows "---", which means that the maximum permissions
available through ACL are 0.
The solution is to set the mask.

# setfacl -m mask:rwx /etc/shadow

Now, when the user "abarclay" attempts to view the contents of the file,
it works as expected:

quake:/home/abarclay$ cat /etc/shadow
root:CaBIGkMFTVD1.:11107::::::
daemon:NP:6445::::::
bin:NP:6445::::::
sys:NP:6445::::::
adm:NP:6445::::::
lp:NP:6445::::::
uucp:NP:6445::::::
nuucp:NP:6445::::::
listen:*LK*:::::::
nobody:NP:6445::::::
noaccess:NP:6445::::::
nobody4:NP:6445::::::
kim:oRECJC5jVN5EY:10554::::::
pwrchute:Q.Rw7noF.d5I2:10556::::::
oracle:5VTye6HhH4xhM:10576::::::
ll:/AhshsnGewa7Y:10950::::::
kovacs:QrSnA5nbT3s.I:10600::::::
dranch:1PPn3MBoWH0jo:10779:10600:::::
abarclay:GdFGraYXdHRys:11108::::::
********************************************

ACLs on directories
-------------------
Applying ACLs to a directory is the same as applying them to a file.

Example
-------
Assume that abarclay is the e-mail administrator for a company.
Mail queues up in /var/spool/mqueue, but the permissions do not allow
non-priviliged users to change to this directory or list its contents.
Lets add read and execute permissions to this directory for abarclay.

$ cd /var/spool/mqueue
ksh: mqueue: permission denied

# setfacl -m user:abarclay:r-x,mask:rwx /var/spool/mqueue

$ cd /var/spool/mqueue
$

$ ls -ld /var/spool/mqueue
drwxr-x---+  2 root     bin          512 Jul 22 23:18 /var/spool/mqueue

$ getfacl /var/spool/mqueue

# file: /var/spool/mqueue
# owner: root
# group: bin
user::rwx
user:abarclay:r-x               #effective:r-x
group::r-x              #effective:r-x
mask:rwx
other:---

Default ACLs on directories
---------------------------
It is also possible to assign certain ACLs to a directory which will
cause any files created inside that directory to have certain ACLs
automatically created.

If a default ACL is set on a directory and there is no specific user or
group name specified, then any files and directories that are
created in the directory will be created with the indicated mode without
respect to the umask. 

Example
-------

$ mkdir /var/tmp/fred
$ setfacl -m default:user::rw-,default:group::r--,default:other:--- \
	/var/tmp/fred

Notice that when assigning "default" ACLs to a directory, you MUST specify
all of user, group, and other entries. "mask" is still optional.

Now, create a file in that directory. The umask is 022, so if the umask
is actually used, then the permissions will be 644. If the umask is ignored,
(as we expect it will be), then the permissions will be 640.

$ touch /var/tmp/fred/foo
quake:/var/spool$ ls -l /var/tmp/fred/foo
-rw-r-----   1 abarclay staff          0 Aug  4 10:50 /var/tmp/fred/foo

Just as we expected!

Interestingly enough, notice that there are no separate ACLs created on the
new file. (no "+" symbol next to the permissions).

Unfortunately, this will result in some really strange behaviour when we
create a directory in /var/tmp/fred

$ mkdir /var/tmp/fred/bar
$ ls -ld /var/tmp/fred/bar
drw-r-----+  2 abarclay staff        512 Aug  4 10:52 /var/tmp/fred/bar

With this mode, not even the owner (abarclay), can change to the newly
created directory!

What we probably want is for the umask to be observed, but for additional
people to have access (or not have access) to the files and directories 
in this directory.

Lets try to restrict access for someone.

First, get rid of the directory and all its contents.
$ rm -rf /var/tmp/fred

Next, create the directory again, and check that the ACLs are gone.
$ mkdir /var/tmp/fred
$ ls -ld /var/tmp/fred
drwxr-xr-x   2 abarclay staff        512 Aug  4 10:56 /var/tmp/fred

Change the owner to root, but leave the group "staff"
# chown root /var/tmp/fred

Assign default ACLs so that abarclay will not have access to files or
directories created in that directory.
# setfacl -m default:user:abarclay:---,default:user::rw-,\
default:group::r--,default:other:---,default:mask:--- /var/tmp/fred

Create a file and a directory in the /var/tmp/fred directory
# touch /var/tmp/foo
# mkdir /var/tmp/bar

For some strange reason, the resulting permissions don't seem to follow
either the umask or the ACL, so just accept this as an ACL quirk and
set the mode appropriately.

$ ls -l /var/tmp/fred
drw-------+  2 root     other        512 Aug  4 11:02 bar
-rw-------+  1 root     other          0 Aug  4 11:02 foo

# chgrp staff /var/tmp/fred/*
# chmod g+r /var/tmp/fred/foo
# chmod g+rx /var/tmp/fred/bar

Now, login as a user "jeff", (a member of the group "staff"), and try to
change to the directory foo (we expect this to work).

$ cd /var/tmp/fred/bar
$

It works as expected!

Now login as user "abarclay" and try to change to the directory.

$ cd /var/tmp/fred/bar
ksh: /var/tmp/fred/bar: permission denied

Even though abarclay is a member of the group "staff", the ACL on the
directory is preventing access.