Introduction

Hello, and welcome back to CS631 "Advanced Programming in the UNIX Environment". This is week three, segment five, where we will take a look at what file ownership and permissions are applied when we create a new file. In the process we learn about the concept of a process's 'umask' and look at how the 'umask' shell built-in is implemented.

Ownership of files

Okay, so far we've covered changing permissions and ownerships and in the process we've repeatedly created new files to work with. But how does the system decide what file ownership and permissions new files should get? The decision making process is a bit easier here: when a new file is created, the new owner of the file is the effective uid of the process. That makes sense. The group ID of the file, however, may depend on the Unix version or how it is configured. On most linux systems, the default setting is to inherit group ownership from the effective group id of the process; on BSD derived systems, the default is to inherit group ownership from the directory in which the file is created. The rationale for this behavior is that in multi-user systems people want to collaborate in groups and the directory owned by a given group should imply group ownership they're in. Let's observe this in practice: we create a new directory under /tmp. The new directory has a group ownership of 'wheel', which is the group ownership of /tmp. Creating a new file under 'dir' should then also get a group ownership of 'wheel'. Ok, looks all right. What if we chown(1) the directory to 'users'? Aha, now the new file is also group owned by 'users', because the directory it was created in was, too. Of course the previous file retains its group ownership. But 'jschauma' is a member of both 'users' and 'wheel'. What if the directory was owned by another group, one jschauma was not a member of? Let's give it a try. Ah, look at that: 'file3' inherited the 'daemon' group ownership from the directory, even though 'jschauma' is not a member of the 'daemon' group. Wait - does that mean I can create files owned by groups I'm not a member of? There, now i have a program that's owned by the 'daemon' group, and I'm the owner of that file, so i should be able to change the permissions. Doesn't that mean I could escalate my privileges to those of the 'daemon' group? Phew, fortunately that doesn't work. Our chmod(2) permissions as discussed earlier still apply. All right, now let's see what this looks like on a linux system. Here we have my home directory and my groups. The new directory has the same group ownership as the current directory, which also happens to be my primary group. If we create a new file, it gets the same group owner. Does this system then also inherit group ownership from the directory? Let's change the group ownership to 'null'. The new file does not inherit group ownership of the directory, but will always get the group ownership from the primary group id of the process, it looks like. As i mentioned, different systems behave differently and it's important to know the difference when administrating them. But okay, that covers default ownership. What about permissions?

umask(2)

For that, we have the 'umask'. A 'umask' is the file creation mode mask in which any bits toggled on are turned off when creating a file. You can set a umask in your process to ensure that any files created later on will have certain default permissions. To do that, you call the umask(2) syscall. Note that the umask only applies to the current process. The system may have a default umask set for new processes that differs from yours, but many of you have probably used the umask shell built-in. Let's run through our last command examples in this video segment, to illustrate how it works.

umask(2) example

Here's our program 'umask.c': in it, we have a call to open(2) that will create a new file with permissions as specified: read, write, exec for the user, group, and others. Recall from our earlier lecture that the permissions specified here are subject to the process's current umask, meaning bits in the umask are turned off at file creation in time, even if open(2) specified them. So the first time we call this function you will have, we will have whatever umask we inherited from the shell. Then we explicitly turn off all bits in the umask, meaning we will allow the permissions the open(2) call has specified; prior to the third call, we set a umask that should turn off group and other permissions. Let's run it. Our current umask is 0022, meaning we want to turn off by default group and other write permissions. When we create a new file, it is created with mode 644, allowing read and write access to the user, but only read access to groups and others. Now we run our program. The resulting file looks like so. Recall that our open(2) call requested read, write, exec permissions for all user, group, and others each time. The first file, file1, our umask turned off the right bits. For file2, we explicitly turned off the umask and then got all the permissions open requested; for file3 we turned off group and other read write permissions, but left exec permissions in place. Let's change our umask to a different value, 077, and try again. 077 means that we disable by default read, write, and exec permissions for group and others, and so our newly created file only gets mode 0600, and our program will create files almost identical to the first time around for the cases where the program set the umask, but different for where it inherited the umask from the shell. Make sense? If not - and even if - play around with setting the umask in your shell to certain values to ensure you understand the effect on newly created files.

Recap

All right, we did it! We learned all about file permissions and ownerships, effective uids and group ids, and changing them and how the system enforces permissions. In this short video, we discussed the umask and how it allows the user to influence the default permissions with which new files are created. With all that, you should now be able to implement most of the chown(1) and chmod(2) commands, as well as the stat(1) command. In fact, come to think of it, with what we've learned so far you should actually be able to write a version of ls(1) that's close to the system's ls(1). You know what? Let's just do that! It'll be your midterm coding assignment and I promise you it'll be fun. Please carefully read the assignment at this url here and we'll discuss it in our next class. In the next video segment, we'll talk a bit about directories as we prepare for our week 4 materials, file systems and a number of mixed system data calls. Thanks for watching, and until next time!

Outro

Cheers!