The umask(2) Function and umask Bits

When new files and directories are created, the designer of the program must decide which permissions to use. These are usually specified as quite liberal permissions. Sometimes greater security is required when you do not want to give away certain permissions to the group or to the world.

Permission Bits

Just by way of review, the permission bit scheme will be presented. Not everyone is used to working with permissions in the octal form, which is the way umask is discussed for convenience.

The data type used for permission bits in modern UNIX systems is the mode_t data type. Under older versions of UNIX, it was the int data type. The permission bits are laid out in three groups:

rwx rwx rwx

Each of the three groupings consists of bits rwx, representing

read permission r
write permission w
execute permission x

respectively. From left to right, the permission groups are

owner permissions u
group permissions g
all others permissions o

The letters u, g, and o are the ones used on the chmod(1) command line when octal notation is not used. Since octal notation encodes each digit with three bits, it proves to be a convenient way to specify the permissions. For example, the octal value 0740 specifies

rwx permissions for the owner u
r permission only for the group g
no permissions for others o

Standards bodies are encouraging programmers not to rely on octal encoding. The C macros in Table 4.1 have been defined for use in programs:

Table 4.1. C Macros for Permission Bits
C Macro Octal Meaning
S_ISUID 04000 Set user ID on execution.
S_ISGID 020#0 Set group ID on execution if # is 7, 5, 3, or 1; enable mandatory file/record locking if # is 6, 4, 2, or 0.
S_ISVTX 01000 Save text image after execution (sticky bit).
S_IRWXU 00700 Read, write, execute by owner.
S_IRUSR 00400 Read by owner.
S_IWUSR 00200 Write by owner.
S_IXUSR 00100 Execute (search if a directory) by owner.
S_IRWXG 00070 Read, write, execute by group.
S_IRGRP 00040 Read by group.
S_IWGRP 00020 Write by group.
S_IXGRP 00010 Execute by group.
S_IRWXO 00007 Read, write, execute (search) by others.
S_IROTH 00004 Read by others.
S_IWOTH 00002 Write by others.
S_IXOTH 00001 Execute by others.

Based on the values in Table 4.1, the permissions 0740 would be defined in macro form as follows:

S_IRWXU | S_IRWXU

Alternatively, it can be spelled out as

S_IRUSR | S_IWUSR | S_IXUSR | S_IRWXU

The permission S_ISVTX (sticky bit) is not supported by FreeBSD for executables, but is supported for directories.

Understanding the Need for umask

Consider an example in which you are working in a student environment with a number of other students on the same machine. You create a program to hand in as an assignment and save it. The vi editor creates the text file with read and write permissions for the owner, the group, and the world. Another enterprising student copies your assignment to his home directory and later hands it in. He can do this because he can read your saved assignment. Because he also has write permission on your text file, he overwrites your file with something else so that you have nothing to hand in. All of this happened because vi gave the owner, the group, and the world permission to read and write the file.

The manner in which the designers of UNIX have chosen to deal with this problem is to allow program designers to specify the most liberal permissions they dare apply for the application involved. Then a mask is applied on a process-level basis to exclude permissions the user does not want to give away. In the example, the student would have been prudent to exclude group and world access to his new files.

Your UNIX process maintains a umask value to allow you to have control over the permissions being handed out. This is a mask value since it is used to mask out certain permission bits that you do not want to give away. To prevent the group or the world from being granted any permission on your top secret new files, you could set the umask value to octal 077. This would allow the umask value to remove any permission at the group and world (other) levels.

Understanding the Scope of umask

The umask value is maintained by the UNIX kernel at the process level. The umask built-in command for the Korn shell sets the umask value for that shell process (in other words, its own process). However, whenever the shell creates a new process, that new process inherits the shell's umask setting. In this manner, setting the umask value in the shell causes it to be set for the entire user session, even in new shell processes.

The scope of the umask value is also limited to file system objects. This means that it applies to files and directories, but it does not apply to IPC objects such as semaphores, message queues, and shared memory.

Using the umask(2) Function

The umask value applies to file system objects. Therefore, whenever your current process creates a new directory or file, the umask value is applied before the final permission bits are established.

In C language terms, the umask value is computed like this:

actual_permissions = requested_permissions & ( ~umask );

The value requested_permissions represents the most liberal set of permissions that might be given in the open(2) call that was covered earlier. Note the use of the unary ~ (tilde) operator to invert the umask bits before using the binary & (and) operator. The resulting actual_permissions bits are the ones then that are actually applied when the file or directory is created.

Example Using the umask Value

If the vi editor was to create a new text file requesting permission bits 0666 (read and write for everyone), and the current umask value was 0077 (exclude group and others), the following computations would occur (successively simplifying):

  1. actual_permissions = requested_permissions & (~umask)

  2. actual_permissions = 0666 & ( ~0077 )

  3. actual_permissions = 0666 & 0700

  4. actual_permissions = 0600

The final permission bits would be computed as 0600, which represents read and write for the owner of the file but no permission for the group or for others.

The umask(2) Function

The umask setting is queried and set by the function umask(2). The function prototype is as follows:

#include <sys/types.h>
#include <sys/stat.h>

mode_t umask(mode_t new_umask);

The value provided in the argument is the new umask value that you want to apply. The value returned is the umask value that was in effect before the current call. The umask(2) function never returns an error.

In the following code, a new umask value of 077 is being established. At the same time, the original umask setting is saved in the variable old_mask:

int old_mask;

old_mask = umask(0077);

Setting umask with umask(2)

The procedure for setting the umask value is as follows:

  1. Call umask(2) with the new mask value.

  2. Save the old umask value if there is a possibility that you need to restore the present umask setting.

The original umask value is frequently saved because it may need to be restored later. This is often done in a library function, where the umask value may need to be temporarily changed.

Querying umask with umask(2)

There is no function to inquire about the umask(2) value. For this reason, you must inquire using a procedure that sets one umask value and then restores the original. This procedure is outlined as follows:

  1. Call umask(2) with a new mask value. Zero will do.

  2. Save the returned value as the present umask value in a variable.

  3. Call umask(2) again, with the original umask value to restore it.

Listing 4.1 shows an example of a function named query_umask(), which performs this very process:

Code Listing 4.1. umask.c—Program Example Querying the umask Value
1:   /* umask.c */
2:
3:   #include <stdio.h>
4:   #include <sys/types.h>
5:   #include <sys/stat.h>
6:
7:   mode_t
8:   query_umask(void) {
9:       mode_t old_umask;
10:
11:      umask(old_umask = umask(0));
12:      return old_umask;
13:  }
14:
15:  int
16:  main(int argc,char **argv) {
17:
18:      printf("umask = %04o
",query_umask());
19:      return 0;
20:  }

The following session shows the compile and run of the example program:

$ make umask
cc -c -D_POSIX_C_SOURCE=199309L -Wall umask.c
cc umask.o -o umask
$ ./umask
umask = 0022
$ umask
0022
$

The program is invoked with the command ./umask, and it reports a mask value of 0022. The shell's built-in umask(1) command is then invoked, and its results agree.

The creat(2) Function

A companion function to the open(2) call is the creat(2) function. Its function synopsis is as follows:

#include <fcntl.h>

int creat(const char *path,mode_t mode);

This function is equivalent to the following open(2) function call:

open(path,O_CREAT|O_TRUNC|O_WRONLY,mode);

This means that creat(2) function will

  • Create the file if necessary

  • Truncate the file to zero bytes of length

  • Open it for writing only

The umask(2) setting will be applied to mode to arrive at the final permissions on the regular file created.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.182.179