Monday, August 15, 2016

Changing File and Directory Access Mode

In Unix-like systems, files and directories have access mode associated with them, which specifies who can do what with the file. The access modes include read(r), write(w), and execute(x) for its owner, group members, and others. Because there are three modes, there would be total 2*2*2 = 2^3 = 8 possible configurations of read, write, and execute flags. They are represented by one bit in a three-bit number as follows: read corresponds to 4 (=100b), write corresponds to 2 (=010b), and execute corresponds to 1 (=001b). Here, proceeding b indicates binary representation.

For example, if the file owner has all the read, write, and execute access, then it would be represented as rwx or 7 (=111b). Similarly, if only read and execute flags are set (enabled), then it would be represented as rx or 5 (=101b), and so on.

Because we have these 3-access-flags associated with its owner, group member, and others, we have total 3*3 = 9 digit binary-number to represent all possible 8*8*8 = 2^(3*3) = 2^9 = 512 configurations. For example, if the owner has read and write access, group member has write access, and others have execute access, then it would be 110 010 001b, where the leading three-bits represent owner access, the next three bits represent group member access, and the last three bits represent others access. Because it is so cumbersome to describe the access mode in terms of 9 bits, Unix represents them in octal representation, i.e., 110 010 001b = 621o, where proceeding o indicates octal representation.

The first dash means it is a regular file, For a directory, the first letter will be d, as can be seen with test_dir. The next three letters represent access mode of the owner, who in this case is linuxnme. Again, dash means no access, so test file has owner's read and write access only, while test_dir has owner's read, write, and execute access. For directories, execute access means search within the directory.

The next three letters represent access mode of the group member, in this case is staff. The last three letters represent access mode for others.

Here, u represents the owner or the user, linuxnme, and +/- sign indicates whether to enable or disable from the current access. For example, u+rx-w means to enable read and execute access but disable write access. In a similar manner, one can use g for group members and o for others. For example, we could do

$ chmod u-r+w,g+w,o-r+x test

$ ls -l test

--w-rw---x@ 1 linuxnme staff 0 Aug 15 18:54 test

We can also use = sign to set it as is. For example,

$ chmod ug=rw,o=x test

$ ls -l test

-rw-rw---x@ 1 linuxnme staff 0 Aug 15 18:54 test

However, it must be obvious that this method requires a bit of typing. Because programmers are lazy, chmod also accepts the octal representation mentioned above. That is,

$ chmod 744 test

$ ls -l test

-rwxr--r--@ 1 linuxnme staff 0 Aug 15 18:54 test

This way makes it very easy, only requiring 3 digits to set access mode in any of the 512 configurations.

Lastly, there are some other extra access modes, which are setuid, setgid, and sticky. Here, setuid access means that executing the file with setuid will run with effective uid of the owner of the file. For example, if the file is executable and owned by root, then running this file from any other user will have effective uid as root, which would be 0. setgid is similar, but pertains to the effective group id. Sticky bit is for shareable executable files and directories, but I won't go into that in this post.

In chmod, u+s will enable setuid and g+s will enable setgid. Also, one can append another octal digit to represent the configurations: 4 for setuid, 2 for setgid, and 1 for sticky. For example,

$ chmod 4755 test

$ ls -l test

-rwsr-xr-x@ 1 linuxnme staff 0 Aug 15 18:54 test

Consider the code below:

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

int main() {

int uid = getuid();

int euid = geteuid();

printf ("uid: %d\neuid: %d\n", uid, euid);

return 0;

}

If you compile the code and run it, the program will output your uid and effective uid. In my case,

linuxnme $ ./a.out

uid: 501

euid: 501

However, if I enable setuid access and run it as a different user, I obtain effective uid equivalent to the owner of the file: