Hello, and welcome back to CS631 "Advanced Programming in the UNIX Environment". This is week 3, segment 5, where we'll take a look at what file ownership and permissions are applied when we create a new file. In the process, we'll learn about the concept of a process's "umask", and look at how the 'umask' shell built-in is implemented. --- So: In our previous segments, 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 new 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 GID 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 on multi-user systems, people want to collaborate in groups, and a directory owned by a given group should imply group ownership therein. 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 alright. What if we chown 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 'daemon'. And I'm the owner of that file, so I should be able to change the permissions. Doesn't that mean that I could escalate my privileges to those of the 'daemon' group? Let's try: Phew, fortunately that doesn't work! Our chmod permissions decisions as discussed earlier still apply. - Alright, 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 I create a new file, it gets the same group owner. Does this system then also inherit group ownership from the directory? Let's change group ownership to 'null'. Aha - the new file does _not_ inherit the 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 ok, that covers default file ownership -- what about permissions? --- 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' 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. While many of you have probably used the 'umask' shell builtin, let's run through our last command examples in this video segment to illustrate how it works: --- 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 time, even if open(2) specified them. The first time we call this function, 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 files look like so: Recall that our open(2) call requested read/write/exec permissions for all user/group/others each time; the first time - file1 -- , our umask turned off the write bits. For file2, we explicitly turned off the umask and thus got all the permissions open(2) requested. For file3, we turned off group and other read/write permissions, but left exec permissions in place. Let's change our umask to 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. --- Alright, we did it! In these last four video segments, we learned all about file permissions and ownerships, effective UIDs and GIDs 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(8) and chmod(8) 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 do just 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; we'll discuss it in our next class. In our next video segment, we'll talk a bit about directories as we prepare for our week 4 materials: filesystems and a number of mixed system data calls. Thanks for watching, and until next time! Cheers!