Managing Users and Permissions
In the previous chapter, we set up our very own Ubuntu Server installation, and we can now learn how to maintain it, starting with a look at managing who is able to use our server.
As administrators of Ubuntu servers, users can be your greatest asset and also your biggest headache. During your career, you’ll add countless new users, manage their passwords, remove their accounts when they leave the company, and grant or remove access to resources across the network. Even on servers on which you’re the only user, you’ll still find yourself managing user accounts, since even system processes run as users. To be successful at managing Linux servers, you’ll also need to know how to manage permissions, create password policies, and limit who can execute administrative commands on the machine. In this chapter, we’ll work through these concepts so that you have a clear idea of how to manage users and their resources.
In particular, we will cover:
- Understanding the purpose of users and groups
- Understanding when to use
root
- Creating and removing users
- Understanding the
/etc/passwd
and/etc/shadow
files - Distributing default configuration files with
/etc/skel
- Switching between users
- Managing groups
- Managing passwords and password policies
- Configuring administrator access with
sudo
- Setting permissions on files and directories
In the first section, we will have a quick discussion about the nature of managing users.
Understanding the purpose of users and groups
When it comes to a server, users are very important—without users to serve, then there’s no real need for a server in the first place. The subject of user management itself within the world of IT is in and of itself quite vast. Entire books have been written on individual methods of authentication, and entire technologies (such as Lightweight Directory Access Protocol, or LDAP) exist around it. In this chapter, we’ll look at managing users that exist locally on our server, and the groups that help define what they are able to do.
Since Ubuntu Server is a distribution of Linux, it adopts the Unix style of managing user accounts, groups, and permissions. Although our focus is on Ubuntu, many of the same commands around user management that you’ll learn in this chapter will apply to other platforms as well. There are commands that allow you to add, remove, and change users, as well as commands that allow you to alter permissions.
Users in the context of a server refer to who (or what) is able to use the server. For example, you may have an accountant named Susan, or an IT administrator named Haneef, who both need to access the server. Perhaps Susan only needs access to a file share directory for accounting-related files, and Haneef might have more access to the server as a system administrator. The user accounts we create on our server will represent the actual people that will use it.
Groups allow us to segregate access to specific files and directories. As we’ll learn later, files and directories have user and group assignments. When combined with permissions, we’ll be able to manage what our users are able to do with our server.
Users aren’t always people, though. We also have system users on our server that applications and running processes might use for background or automated tasks. An example of this might be a backup job, and you may have a backup user that runs a task in the background to facilitate some sort of file copy task that copies important files to another place. You don’t have to worry about system-related users for now, just know that they exist. You’ll see more examples of this as we go through the book.
More advanced organizations may have a central login server, such as Active Directory (AD) or standard LDAP. There are others aside from those, as well. In this book, we won’t cover those technologies, but just keep in mind that central authentication servers are a possibility for your organization, should you choose to explore them.
The most powerful user of all, though, is root
. This special user gives us the most control, but as you’ll see in the next section, that comes with risks.
Understanding when to use root
In the last chapter, we set up our very own Ubuntu Server installation. During the installation process, we were instructed to create a user account to act as a system administrator. So, at this point, we should have at least two users on our server. We have the aforementioned administrative user, as well as root
. We can certainly create additional user accounts with varying levels of access (and we will do so in this chapter), but before we get to that, some discussion is in order regarding the administrator account you created, as well as the root
user that was created for you.
The root
user account exists on all Linux distributions and is the most powerful user account on the planet. The root
user account can be used to do anything within your server, and I do mean anything. Want to create files and directories virtually anywhere on the filesystem? Want to install software? These processes are easily performed with root
. The root
account can even be used to destroy your entire installation with one typo or ill-conceived command: if you instruct root
to delete all the files on your entire hard disk, it won’t hesitate to do so. It’s always assumed on a Linux system that if you are using root
, you are doing so because you know what you are doing. So, there’s often not so much as a confirmation prompt while executing any command as root
. It will simply do as instructed, for better or worse.
It’s for this reason that every Linux distribution I’ve ever used has stated, or at least highly recommended, that you create a standard user during the installation process. It’s generally recommended in the Linux community for an administrator to have their own account and then switch to root
whenever a task comes up that requires root
privileges to complete. This approach is less likely to destroy your server with an accidental typo or bad command. Some administrators will strictly use root
at all times without any issue, but again, it’s recommended to use root
only when you have to.
Most distributions ask you to create a root
password during installation in order to protect that account. Even Debian (on which Ubuntu is based) has you set a root
password during installation. Ubuntu just decides to do things a little bit differently. The reason for this is that, unlike many other distributions, Ubuntu defaults to locking out the root
account altogether. There’s nothing stopping you from enabling root
, or switching to the root
user after you log in. Being disabled by default just means the root
account isn’t as easily accessible as it normally would be. I’ll cover how to enable this account later in this chapter, should you feel the need to do so.
An exception to this rule is that some VPS providers, such as Linode, will enable the root
account even on their Ubuntu servers. Sometimes, the root
password will be randomly generated and emailed to you. However, you should still create a user for yourself with administrative access regardless.
Instead of using root
outright, Ubuntu (as well as its server version) recommends the use of sudo
. Specifically, sudo
enables you to run individual commands with elevated privileges instead of being logged in as root
all the time.
Using sudo to run privileged commands
I’ll go over how to manage sudo
later on in this chapter, but for now, just keep in mind that the purpose of sudo
is to enable you to use your user account to do things that normally only root
would be able to do. For example, as a normal user, you cannot issue a command such as the following to install a software package (don’t worry about the apt
command for now, as we’ll cover that in Chapter 3, Managing Software Packages):
apt install tmux
Instead, you’ll receive an error:
E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?
But if you prefix the command with sudo
(assuming your user account has access to it), the command will work just fine:
sudo apt install tmux
When you use sudo
, you’ll be asked for your user’s password for confirmation, and then the command will execute. Subsequent commands prefixed with sudo
may not prompt for your password, as it will cache your password for a short period of time until it times out or the terminal is closed. Understanding this should clarify the usefulness of the user account you created during installation. I referred to this user as an administrative account earlier, but it’s really just a user account that is able to utilize sudo
. Ubuntu Server automatically gives the first user account you create during installation access to sudo
.
The intent is that you’ll use that account to administer the system, rather than root
. When you create additional user accounts, they will not have access to sudo
by default, unless you explicitly grant it to them.
Creating and removing users
Creating users in Ubuntu can be done with one of two commands: adduser
and useradd
. This can be a little confusing at first, because both of these commands do the same thing (in different ways) and are named very similarly. I’ll go over the useradd
command first and then I’ll explain how adduser
differs. You may even prefer the latter, but we’ll get to that in a moment.
Using useradd
First, here’s an example of the useradd
command in action:
sudo useradd -d /home/jdoe -m jdoe
With this command, I created a user named jdoe
. With the -d
option, I’m clarifying that I would like a home directory created for this user, and following that, I called out /home/jdoe
as the user’s home directory. The -m
flag tells the system that I would like the home directory to be created during the process; otherwise, I would’ve had to create the directory myself. Finally, I called out the username for my new user (in this case, jdoe
).
As we go along in this book, there will be commands that require root
privileges in order to execute. The preceding command was an example of this. For commands that require such permissions, I’ll prefix the commands with sudo
. When you see these, it just means that root
privileges are required to run the command. For these, you can also log in as root
(if root
is enabled) or switch to root
to execute these commands as well. However, as I mentioned before, using sudo
instead of using the root
account is strongly encouraged.
Now, list the storage of /home
using the following command:
ls -l /home
You should see a folder listed there for our new user:

Figure 2.1: Listing the contents of /home after our first user was created
What about creating our user’s password? We may have been asked for our current user’s password due to using sudo
, but we weren’t asked for a password for the new user. To create a password for the user, we can use the passwd
command. The passwd
command defaults to allowing you to change the password for the user you’re currently logged in as, but it also allows you to set a password for any other user if you run it as root
or with sudo
. If you enter passwd
by itself, the command will first ask you for your current password, then your new password, and then it will ask you to confirm your new password again. If you prefix the command with sudo
and then specify a different user account, you can set the password for any user you wish. An example of the output of this process is as follows:

Figure 2.2: Changing the password of a user
As you can see in the previous screenshot, you won’t see any asterisks or any kind of output when you type a password using the passwd
command. This is normal. Although you won’t see any visual indication of input, your input is being recognized.
Now we have a new user and we were able to set a password for that user. The jdoe
user will now be able to access the system with the password we’ve chosen. This user won’t have access to sudo
by default, but we’ll cover how to change this later on in the chapter.
Using adduser
Earlier, I mentioned the adduser
command as another way of creating a user. The difference (and convenience) of this command should become apparent immediately once you’ve used it. Go ahead and give it a try; execute adduser
along with a username for a user you wish to create. An example run of this process is as follows:

Figure 2.3: Creating a user with the adduser command
In the preceding process, I executed sudo adduser dscully
(commands that modify users require sudo
or root
) and then I was asked a series of questions regarding how I wanted the user to be created. I was asked for the password (twice), Full Name
, Room Number
, Work Phone
, and Home Phone
. In the Other
field, I entered the comment Trust no one
, which is a great mindset to adopt while managing users. The latter prompts prior to the final confirmation were all optional: I didn’t have to enter Full Name
, Room Number
, and so on. I could’ve pressed Enter to skip those prompts if I wanted to. The only things that are really required are the username and the password.
From the output, we can see that the adduser
command performed quite a bit of work for us. The command defaulted to using /home/dscully
as the home directory for the user, the account was given the next available User ID (UID) and Group ID (GID) of 1002
, and it also copied files from /etc/skel
into our new user’s home
directory. In fact, both the adduser
and useradd
commands copy files from /etc/skel
, but adduser
is more verbose regarding the actions it performs.
Don’t worry if you don’t understand what UID
, GID
, and /etc/skel
are yet. We’ll work through those concepts soon.
In a nutshell, the adduser
command is much more convenient in the sense that it prompts you for various options while it creates the user without requiring that you memorize command-line options. It also gives you detailed information about what it has done. At this point, you may be wondering why someone would want to use useradd
at all, considering how much more convenient adduser
seems to be. Unfortunately, adduser
is not available on all distributions of Linux. It’s best to familiarize yourself with useradd
in case you find yourself on a Linux system that’s not Ubuntu.
It may be interesting for you to see what exactly the adduser
command is. It’s not even a binary program—it’s a shell script. A shell script is simply a text file that can be executed as a program. You don’t have to worry too much about scripting now, as we will cover it in Chapter 6, Boosting Your Command-line Efficiency. In the case of adduser
, it’s a script written in Perl, which is a programming language that is sometimes used for administrative tasks. Since it’s not binary, you can even open it in a text editor in order to view all the code that it executes behind the scenes. However, make sure you don’t open the file in a text editor with root
privileges, to ensure that you don’t accidentally save changes to the file and break the script. The following command will open adduser
in a text editor on an Ubuntu Server system:
nano /usr/sbin/adduser
Use your up/down arrows as well as the Page Up and Page Down keys to scroll through the file. When you’re finished, press Ctrl + x on your keyboard to exit the text editor. If the editor prompts you to save changes, don’t do so. Anyway, those of you with keen eyes will likely notice that the adduser
script is calling useradd
to perform its actual work. So either way, you’re either directly or indirectly using useradd
.
Now that we know how to create users, it will be useful to understand how to remove them as well.
Removing users
Removing or disabling an account is very important when a user no longer needs to access a system, as unmanaged accounts often become a security risk. To remove a user account, we’ll use the userdel
command.
Before removing an account, though, there is one very important question you should ask yourself. Will you (or another person) need access to the user’s files? Most companies have retention policies in place that detail what should happen to a user’s data when they leave the organization. Sometimes, these files are copied into an archive for long-term storage. Often, a manager, coworker, or new hire will need access to the former user’s files, perhaps to continue working on a project where they left off. It’s important to understand this policy ahead of managing users. If you don’t have a policy in place that outlines retention requirements for files when users resign, you should probably work with your management team and create one.
By default, the userdel
command does not remove the contents of the user’s home
directory. Here, we use the following command to remove dscully
from the system:
sudo userdel dscully
We can see that the files for the dscully
user still exist by entering the following command:
ls -l /home
The preceding commands will result in the following outputs:

Figure 2.4: The home directory for the user dscully still exists, even though we removed the user
With the /home
directory for dscully
still existing, we’re able to move the contents of this directory anywhere we would like to. If we had a directory called /store/file_archive
, for example, we could easily move the files there:
sudo mv /home/dscully /store/file_archive
Of course, it’s up to you to create the directory where your long-term storage will ultimately be, but you get the idea.
If you weren’t already aware, you can create a new directory with the mkdir
command. You can create a directory within any other directory that your logged-in user has access to. The following command will create the file_archive
directory I mentioned in the preceding example:
sudo mkdir -p /store/file_archive
The -p
flag simply creates the parent directory if it didn’t already exist.
If you do actually want to remove a user’s home directory at the same time that you remove an account, just add the -r
option. This will eliminate the user and their data in one shot:
sudo userdel -r dscully
To remove the /home
directory for the user after the account was already removed (if you didn’t use the -r
parameter the first time), use the rm -r
command to get rid of it, as you would any other directory:
sudo rm -r /home/dscully
It probably goes without saying, but the rm
command can be extremely dangerous. If you’re logged in as root
or using sudo
while using rm
, you can easily destroy your entire installed system if you’re not careful. DO NOT run this command, but as a hypothetical example, the following command (while seemingly innocent at first glance) will likely completely destroy your entire filesystem:
sudo rm -r / home/dscully
Notice the typo: I accidentally typed a space after the first forward slash. I literally accidentally told my system to remove the contents of the entire filesystem. If that command were executed, the server probably wouldn’t even boot the next time we attempted to start it. All user and program data would be wiped out. If there was ever any single reason for us to be protective over the root
account, the rm
command is most certainly it!
At this point, we understand how to add and remove users. In the next section, we’ll look deeper into passwords.
Understanding the /etc/passwd and /etc/shadow files
Now that we know how to create (and delete) user accounts on our server, we are well on our way to being able to manage our users. But where exactly is this information stored? We know that users store their personal files in /home
, but is there some kind of database somewhere that keeps track of which user accounts are on our system? Actually, user account information is stored in two special text files:
/etc/passwd
/etc/shadow
You can display the contents of each of those two files with the following commands. Note that any user can look at the contents of /etc/passwd
, while only root
has access to /etc/shadow
:
cat /etc/passwd
sudo cat /etc/shadow
Go ahead and take a look at these two files (just don’t make any changes), and I will help you understand them.
Understanding the /etc/passwd file
First, let’s go over the /etc/passwd
file. What follows is some example output from this file on my test server. For brevity, I have limited the output to the last eight lines:

Figure 2.5: Example /etc/passwd file
Each line within this file corresponds to a user account on the system. Entries are split into columns, separated by a colon (:
). The username is in the first column, so you can see that I’ve created users jay
and jdoe
. The next column on each is simply an x
. I’ll go over what that means a bit later. For now, let’s skip to the third and fourth columns, which reference the UID and GID respectively.
On a Linux system, user accounts and groups are actually referenced by their IDs. While it’s easier for you and I to manage users by their names, usernames and group names are nothing more than a label placed on the UID and GID in order to help us identify them more easily.
For example, it may be frustrating to try to remember that jdoe
is UID 1001
on our server each time we want to manage this account. Managing it by referring to the account as jdoe
is easier for humans, since we don’t remember numbers as well as we do names. But to Linux, each time we reference user jdoe
, we’re actually just referencing UID 1001
. When a user is created, the system (by default) automatically assigns the next available UID to the account. If you manage multiple Ubuntu servers, note that the UIDs will not match from one system to another, so keep in mind that UIDs don’t synchronize between installations.
In my case (as shown in Figure 2.5), the UID of each user is the same as their GID. This is just a coincidence on my system and it isn’t always that way in practice. While I’ll discuss creating groups later in this chapter, understand that creating groups works in a similar way to creating users, in the sense that the group is assigned the next available GID in much the same way as new user accounts are assigned the next available UID. When you create a user, the user’s primary group is the same as their username (unless you request otherwise). For example, when I created jdoe
, the system also automatically created a jdoe
group as well.
This is what you’re actually seeing here—the UID for the user, as well as the GID for the user’s primary group. Again, we’ll get to groups in more detail later.
You probably also noticed that the /etc/passwd
file on your system contains entries for many more users than the ones we’ve created ourselves. This is perfectly normal, as Linux uses user accounts for various processes and services that run in the background. You’ll likely never interact with the default accounts at all, though you may someday create your own system user for a process to run as. For example, perhaps you’ll create a data processor account for an automated data-processing script to run under.
Anyway, back to our /etc/passwd
file. The fifth column is designated for user info, most commonly the user’s first and last names. In my example, the fifth field is blank for jdoe
, as I created jdoe
with the useradd
command, which didn’t prompt me for the first and last names. This field is also nicknamed the GECOS
field, and you may see it referred to as such when you read the documentation.
In the sixth column, the home directory for each user is shown. In the case of jdoe
, it’s set as /home/jdoe
. Finally, we designate the user’s shell as /bin/bash
. This field refers to the default shell the user will use, which defaults to /bin/bash
when an account is created with the adduser
command, and /bin/sh
when created with the useradd
command. (If you have no preference, /bin/bash
is the best choice for most.) If we want the user to use a different shell, we can clarify that here (though shells other than /bin/bash
aren’t covered in this book). If we wanted, we could change the user’s shell to something invalid to prevent them from logging in at all. This is useful for when a security issue requires us to disable an account quickly.
Understanding the /etc/shadow file
With that out of the way, let’s take a look at the /etc/shadow
file. We can use cat
to display the contents like any other text file, but unlike /etc/passwd
, we need root
privileges in order to view it. So, go ahead and display the contents of this file, and I’ll walk you through it:
sudo cat /etc/shadow
This will display the following output:

Figure 2.6: Example /etc/shadow file
The preceding screenshot, Figure 2.6, shows the last four lines of this file on my server. First, we have the username in the first column—no surprises there. Note that the output is not showing the UID for each user in this file. The system knows which username matches which UID based on the /etc/passwd
file, so there’s no need to repeat that here. In the second column, we have what appears to be gobbledygook. Actually, that’s the most important part of this entire file. That’s the actual hash for the user’s password.
A password hash is a conversion of the actual password to a different string that represents the original password. This is a one-way conversion, so you cannot find the actual password by reverse-engineering the hash. In the /etc/passwd
file, the hash of the password is stored rather than the actual password, for security purposes.
If you recall, in the /etc/passwd
file, each user listing had an x
for the second column, and I mentioned I would explain that later. What the x
refers to is the fact that the user’s password is encrypted and simply not stored in /etc/passwd
and is instead stored in /etc/shadow
. After all, the /etc/passwd
file is viewable by everyone, so it would compromise security quite a bit if anyone could just open up the file and see what everyone’s passwords were.
In the days of old, you could actually store a user’s password in /etc/passwd
, but it’s never done that way anymore. Whenever you create a user account on a modern Linux system, the user’s password is encrypted (an x
is placed in the second column of /etc/passwd
for the user), and the actual password hash is stored in the second column of /etc/shadow
to keep it away from prying eyes. Hopefully, now the relationship between these two files has become apparent.
Remember earlier I mentioned that the root
user account is locked out by default? Well, let’s actually see that in action. Execute the following command to see the root
user account entry in /etc/shadow
:
sudo cat /etc/shadow | grep root
On my system, I get the following output:

Figure 2.7: Example /etc/shadow file
You should notice right away that the root
user account doesn’t have a password hash at all. Instead, there’s an asterisk where the password hash would’ve been. In practice, placing an asterisk or exclamation point here is one way to lock an account. Even easier, you can use the passwd -l
command against an account to lock it without having to edit a file. But either way, we can still switch to the root
account anytime (which I’ll show you how to do later on in this chapter). Entering an asterisk or exclamation mark in the second field creates the restriction that we can’t directly log in as that user from the shell or over the network. We have to log in to the system as a normal user account first, and then we can still switch to that user if we want to.
With the discussion of password hashes out of the way, there are a few more fields within /etc/shadow
entries that we should probably understand. Here’s a contrived example line:
mulder:$6$TPxx8Z.:16809:0:99999:7:::
Continuing on with the third column, we can see the number of days since the Unix epoch that the password was last changed. For those that don’t know, the Unix epoch is January 1, 1970. Therefore, we can read that column as the password having last been changed 16,809 days after the Unix epoch.
Personally, I like to use the following command to show more easily when the password was last changed:
sudo passwd -S <username>
This will result in an output that looks something like the following:

Figure 2.8: Checking the date of the last password change for a user
By executing this command, you can view information about any account on your system. The first column is obviously the username. The second has to do with the status of the password, which in this case is L
, which refers to the fact that the user has a password that is locked. It would show P
if the password was set and usable, or NP
if the user didn’t have a password at all.
The third column of this command’s output gives you the actual date of the last password change for the user. The fourth column tells us how many days are required to pass before the user will be able to change their password again. In this example, jdoe
can change the password any time because the minimum number of days is set to 0
. We’ll talk about how to set the minimum number of days later on in this chapter, but I’ll give you a brief explanation of what this refers to. At first, it may seem silly to require a user to wait a certain number of days to be able to change their password. However, never underestimate the ability of your users to be oppositional. It’s quite common for a user, when required to change their password, to change their password to satisfy history requirements, only to then just change it back to what it was originally. By setting a minimum number of days, you’re forcing a waiting period in between password changes, making it less convenient for your users to cycle back through to their original password.
The fifth column, as you can probably guess, is the maximum number of days that can pass between password changes. If you require your users to change their passwords every certain number of days, you’ll see that in this column. By default, this is set to 99999
days. That number of days is way beyond the human lifespan, so it may as well be infinite.
Continuing with the sixth column, we have the number of days that will elapse before the expiration date on which the user is warned that they will soon be required to change their password. In the seventh column, we set how many days can pass after the password expires, in which case the account will be disabled. With our example user, this is not set. Finally, with the eighth column (which is not visible), we can see the number of days since the Unix epoch that will elapse before the account is disabled (in our case, there’s nothing here, so there is no disabled day set).
We’ll go over setting these fields later, but for now, hopefully you understand the contents of the /etc/shadow
file better.
If at any time you’d like additional clarification, feel free to check out the Ubuntu man pages. A man page (short for manual page) can give you quite a bit more information about commands as well as files. For example, the following command shows you the man page for the ls
command:
man ls
More specific to this section, you can retrieve man pages for the /etc/shadow
files as well:
man passwd
man shadow
Press q on your keyboard to exit out of a man page. Feel free to check out the man pages for any command in this book to learn more as you go along.
Now that we fully understand how to manage our users, we can also look at how to provide them with default files in their home directory.
Distributing default configuration files with /etc/skel
In a typical organization, there are usually some defaults that are recommended for users in terms of files and configuration.
For example, in a company that performs software development, there are likely recommended settings for text editors and version control systems. Files that are contained within /etc/skel
are copied into the home directory for all new users when you create them (assuming you’ve chosen to create a home directory while setting up the user).
In fact, you can see this for yourself right now. Execute the following command:
ls -la /etc/skel
Now, you should be able to view the contents of the /etc/skel
directory:

Figure 2.9: Default /etc/skel files
You probably already know how to list files within a directory, but I added the -a
option because I wanted to view hidden files as well. The files included in /etc/skel
by default are hidden (their filenames begin with a period). I threw in the -l
parameter solely because it shows a long list, which I think is easier to read.
Each time you create a new user and request a home directory to be created as well, these three files, shown in Figure 2.9, will be copied into their home directory, along with any other files you create here. You can verify this by listing the storage of the home directories for the users you’ve created so far. The .bashrc
file in one user’s home directory should be the same as any other, unless they’ve made changes to it.
Armed with this knowledge, it should be extremely easy to create default files for new users that you create. For example, you could create a file named welcome
with your favorite text editor and place it in /etc/skel
. Perhaps you may create this file to contain helpful phone numbers and information for new hires in your company. The file would then be automatically copied to the new user’s home directory when you create the account. The user, after logging in, would see this file in their home directory and see the information. More practically, if your company has specific editor settings that are favored for writing code, you can include those files in /etc/skel
as well to help ensure your users are compliant. In fact, you can include default configuration files for any application your company uses.
Go ahead and give it a try. Feel free to create some random text files and then create a new user afterward, and you’ll see that these files will propagate into the home directories of the new user accounts that you add to your system.
Now that we have multiple users and have also seen how to manage their default files, we can take a look at how to switch from one user to another.
Switching users
Now that we have several users on our system, we need to know how to switch between them. Of course, you can always just log in to the server as one of the users, but you can actually switch to any user account at any time, provided you either know that user’s password or have sudo
access.
The command you will use to switch from one user to another is the su
command. If you enter su
with no options, it will assume that you want to switch to root
and will ask you for the root
password. As I mentioned earlier, Ubuntu locks the root
account by default, so at this point you may not have a root
password.
Even though Ubuntu doesn’t create a password for root
by default, some Virtual Private Server (VPS) providers unlock the root
password and actually have you log in as the root
user. Having an unlocked root
account is not a standard Ubuntu practice, and is a customization specific to some cloud providers.
Unlocking the root
account is actually really simple; all you have to do is create a root
password. To do that, you can execute the following command as any user with sudo
access:
sudo passwd
The command will ask you to create and confirm your root
password. From this point on, you will be able to use the root
account as any other account. You can log in as root
or switch to root
—it’s fully available now. However, you really don’t have to unlock the root
account in order to use it. You certainly can, but there are ways to switch to root
without unlocking it, and it’s typically better to leave the root
account locked unless you have a very specific reason to unlock it. The following command will allow you to switch to root
from a user account that has sudo
access:
sudo su -
Now you’ll be logged in as root
and will be able to execute any command you want with no restrictions whatsoever. To return to your previously logged-in account, simply type exit
. You can tell which user you’re logged in as by the value at the beginning of your bash
prompt.
What if you want to switch to an account other than root
? Of course, you can simply log out and then log in as that user. But you really don’t have to do that. The following command will do the job, providing you know the password for the account:
su - <username>
The shell will ask for that user’s password and then you’ll be logged in as that user. Again, type exit
when you’re done using the account, which will return you to the one you were using before you switched.
That command is all well and good if you know the user’s password, but you often won’t. Typically, in an enterprise, you’ll create an account, force the user to change their password at first login, and then you will no longer know that user’s password.
Since you have root
and sudo
access, you could always change their password and then log in as them. But they’ll know something is amiss if their password suddenly stops working—you’re not eavesdropping, are you? Armed with sudo
access, you can use sudo
to change to any user you want to, even if you don’t know their password. Just prefix our previous command with sudo
and you’ll only need to enter the password for your user account, instead of theirs:
sudo su - <username>
Switching to another user account is often very helpful for support (especially while troubleshooting permissions). As an example, say that a user comes to you complaining that they cannot access the contents of a specific directory, or they are unable to run a command. In that case, you can log in to the server, switch to their user account, and try to reproduce their problem. That way, you can not only see their problem yourself, but you can also test out whether or not your fix has solved their issue before you report back to them.
Now we have a full understanding of user accounts, and even how to switch between them. In the next section, we’ll look into groups, which allow us to categorize our users.
Managing groups
Now that we understand how to create, manage, and switch between user accounts, we’ll need to understand how to manage groups as well. The concept of groups in Linux is not very different from other platforms and pretty much serves the exact same purpose. With groups, you can more efficiently control a user’s access to resources on your server. By assigning a group to a resource (a file, a directory, and so on), you can allow and disallow access to users by simply adding them or removing them from the group.
The way this works in Linux is that every file or directory has both a user and a group that takes ownership of it. This is contrary to platforms such as Windows, which can have multiple groups assigned to a single resource. With Linux, it’s just one-to-one ownership: just one user and just one group assigned to each file or directory. If you list the contents of a directory on a Linux system, you can see this for yourself:
ls -l
The following is a sample line of output from a directory on one of my servers:
-rw-r--r-- 1 root bind 490 2022-04-15 22:05 named.conf
In this case, we can see that root
owns the file and that the group bind
is also assigned to it. Ignore the other fields for now; I’ll explain them later when we get to the section of this chapter dedicated to permissions. For now, just keep in mind that one user and one group are assigned to each file or directory.
While each file or directory can only have one group assignment, any user account can be a member of any number of groups. Entering the groups
command by itself with no options will tell you what groups your logged-in user is currently a member of. If you add a username to the groups
command, you’ll see which groups that user is a member of. Go ahead and give the groups
command a try with and without providing a username to get the idea.
On the Ubuntu Server platform, you’ll likely see that each of your user accounts is a member of a group that’s named the same as your username. As I mentioned earlier, when you create a user account, you’re also creating a group with the same name as the user. On some Linux distributions, though, a user’s primary group will default to a group called users
instead. If you were to execute the groups
command as a user on the Ubuntu desktop platform, you would likely see additional groups. This is due to the fact that distributions of Linux that cater to being a server platform are often more stripped down and users on desktop platforms need access to more objects such as printers, audio cards, and so on. Some packages that can be installed also add additional system users to the server.
If you were curious as to which groups exist on your server, all you would need to do is cat
the contents of the /etc/group
file. Similar to the /etc/passwd
file we covered earlier, the /etc/group
file contains information regarding the groups that have been created on your system. Go ahead and take a look at this file on your system:
cat /etc/group
The following is sample output from this file on one of my servers:

Figure 2.10: Sample output from the /etc/group file
Like before, the columns in this file are separated by colons, though each line is only four columns long. In the first column, we have the name of the group. No surprise there. In the second, we are able to store a password for the group, but this is not used often as it’s actually a security risk to do so. In the third column, we have the GID, which is similar in concept to the UID from when we were discussing users. Finally, in the last column, we (would) see a comma-separated list of each user that is a member of each of the groups.
Several entries don’t show any group memberships at all. Each user is indeed a member of their own group, so this is implied even though it doesn’t explicitly call that out in this file. If you take a look at the /etc/passwd
entries for your users, you will see that their primary group (shown as the third column in the form of a GID) references a group contained in the /etc/group
file.
Creating new groups on your system is easy to do and is a great idea for categorizing your users and what they are able to do. Perhaps you create an accounting
group for your accountants, an admins
group for those in your IT department, and a sales
group for your salespeople. The groupadd
command allows you to create new groups.
If you wanted to, you could just edit the /etc/group
file and add a new line with your group information manually, although, in my opinion, using groupadd
saves you some work and ensures that group entries are created properly. Editing group and user files directly is typically frowned upon (and a typo can cause serious problems). Anyway, what follows is an example of creating a new group with the groupadd
command:
sudo groupadd admins
If you take a look at the /etc/group
file again after adding a new group, you’ll see that a new line was created in the file and a GID
was chosen for you (the first one that hadn’t been used yet). Removing a group is just as easy. Just issue the groupdel
command followed by the name of the group you wish to remove:
sudo groupdel admins
Next, we’ll take a look at the usermod
command, which will allow you to actually associate users with groups. The usermod
command is more or less a Swiss Army knife; there are several things you can do with that command (adding a user to a group is just one of its abilities). If we wanted to add a user to our admins
group, we would issue the following command:
sudo usermod -aG admins myuser
In that example, we’re supplying the -a
option, which means append, and immediately following that, we’re using -G
, which means we would like to modify secondary group membership. I put the two options together with a single dash (-aG
), but you could also issue them separately (-a -G
). The example I gave only adds the user to additional groups; it doesn’t replace their primary group.
Be careful not to miss the -a
option here, as by doing so, you will instead replace all current group memberships with the new one, which is usually not what you want. The -a
option means append, or to add the existing list of group memberships for that user.
If you wanted to change a user’s primary group, you would use the -g
option instead (lowercase g instead of an uppercase G as we used earlier):
sudo usermod -g <group-name> <username>
Feel free to check out the man pages for the usermod
command, to see all the nifty things it allows you to manage relating to your users. You can peruse the man page for the usermod
command with the following command:
man usermod
One additional example is changing a user’s /home
directory. Suppose that one of your users has undergone a name change, so you’d like to change their username, as well as moving their previous home
directory (and their files) to a new one. The following commands will take care of that:
sudo usermod -d /home/jsmith jdoe -m
sudo usermod -l jsmith jdoe
In that example, we’re moving the home directory for jdoe
to /home/jsmith
, and then in the second example, we’re changing the username from jdoe
to jsmith
.
If you wish to remove a user from a group, you can use the gpasswd
command to do so. gpasswd -d
will do the trick:
sudo gpasswd -d <username> <grouptoremove>
In fact, gpasswd
can also be used in place of usermod
to add a user to a group:
sudo gpasswd -a <username> <group>
So, now you know how to manage groups. With the efficient management of groups, you’ll be able to manage the resources on your server better. Of course, groups are relatively useless without some explanation of how to manage permissions (otherwise, nothing would actually allow a member of a group access to a resource). Later on in this chapter, we’ll cover permissions so that you have a complete understanding of how to manage user access.
Managing passwords and password policies
In this chapter, we’ve already covered a bit of password management, since I’ve given you a few examples of the passwd
command. If you recall, the passwd
command allows us to change the password of the currently logged-in user. In addition, using passwd
as root
(and supplying a username) allows us to change the password for any user account on our system. But that’s not all this command can do.
Locking and unlocking user accounts
One thing I’ve neglected to mention regarding the passwd
command is the fact that you can use it to lock and unlock a user’s account. There are many reasons why you may want to do this. For instance, if a user is going on vacation or extended leave, perhaps you’d want to lock their account so that it cannot be used while they are away. After all, the fewer active accounts, the smaller your attack surface. To lock an account, use the -l
option:
sudo passwd -l <username>
And to unlock it, use the -u
option:
sudo passwd -u <username>
However, locking an account will not prevent the user from logging in if they have access to the server via SSH while utilizing public key authentication. In that case, you’d want to remove their ability to use SSH as well. One common way of doing this is to limit SSH access to users who are members of a specific group. When you lock an account, simply remove them from the group. Don’t worry so much about the SSH portion of this discussion if this is new to you. We will discuss securing your SSH server in Chapter 21, Securing Your Server. For now, just keep in mind that you can use passwd
to lock or unlock accounts, and if you utilize SSH, you’ll want to lock your users out of that to prevent them from logging in.
However, there’s more to password management than the passwd
command, as we can also implement our own policies, such as viewing or adjusting password expiration details.
Setting password expiration information
Earlier, I mentioned that you can set an expiration date on a user’s password (during our discussion on the /etc/shadow
file). In this section, we’ll go through how to actually do that. Specifically, the chage
command gives us this ability. We can use chage
to alter the expiration period of a user’s password, but it’s also a more convenient way of viewing current expiration information than viewing the /etc/shadow
file. With the -l
option of chage
, along with providing a username, we can see the relevant info:
sudo chage -l <username>
Using sudo
or root
is not required to run chage
. You’re able to view expiration information for your own username without needing to escalate permissions. However, if you want to view information via chage
for any user account other than your own, you will need to use sudo
.
In the example that follows, we can see the output of this command from a sample user account:

Figure 2.11: Output from the chage command
In the output, we can see values for the date of expiration, the maximum number of days between password changes, and so on. Basically, it’s the same information stored in /etc/shadow
but it’s much easier to read.
If you would like to change this information, chage
will again be the tool of choice. The first example I’ll provide is a very common one. When creating user accounts, you’ll certainly want them to change their password when they first log in.
Unfortunately, not everyone will be keen on doing so. The chage
command allows you to force a password change for a user when they first log in. Basically, you can set their number of days to expiry to 0
as follows:
sudo chage -d 0 <username>
You can see the results of this command immediately if you run chage -l
again against the user account you just modified:
sudo chage -l <username>
The output will display information regarding the password change:

Figure 2.12: The chage command listing a user that has a required password change period set
To set a user account to require a password change after a certain period of days, the following will do the trick:
sudo chage -M 90 <username>
In that example, I’m setting the user account to expire and require a password change in 90 days. When the impending date reaches 7 days before the password is to be changed, the user will see a warning message when they log in.
As I mentioned earlier, users will often do whatever they can to cheat password requirements and may try to change their password back to what it was originally after satisfying the initially required password change. You can set the minimum number of days with the -m
flag, as you can see in the next example where we set it to 5 days:
sudo chage -m 5 dscully
The trick with setting a minimum password age is to set it so that it will be inconvenient for the user to change their password to the original one, but you still want a user to be able to change their password when they feel the need to (so don’t set it too long, either). If a user wants to change their password before the minimum number of days elapses (for example, if your user feels that their account may have been compromised), they can always have you change it for them. However, if you make your password requirements too much of an inconvenience for your users, it can also work against you.
Setting a password policy
Next, we should discuss setting a password policy. After all, forcing your users to change their passwords does little good if they change it to something simple, such as abc123
. A password policy allows you to force requirements on your users for things such as length, complexity, and so on.
To facilitate this, we have Pluggable Authentication Module (PAM) at our disposal. PAM gives us additional functionality and control over the process of authentication, and also provides additional plugins we can use to extend authentication and add additional features. Although a full walkthrough of PAM isn’t covered in this book, I recommend keeping it fresh in your mind in case you want to add additional features later.
Specific to the subject of setting up a password policy, we can install a PAM module to enable this, which involves installing a new package:
sudo apt install libpam-cracklib
Next, let’s take a look at the following file, which is provided with Ubuntu. Feel free to open it with a text editor, such as nano
, as we’ll need to edit it:
sudo nano /etc/pam.d/common-password
An extremely important tip while modifying configuration files related to authentication (such as password requirements, sudo
access, SSH, and so on) is to always keep a root
shell open at all times while you make changes, and in another shell, test those changes. Do not log out of your initial root
window until you are 100% certain that your changes have been thoroughly tested. While testing a policy, make sure that not only can your users log in, but your admins too. Otherwise, you may remove your ability to log in to a server and make changes.
To enable a history requirement for your passwords (meaning the system remembers the last several passwords a user has used, preventing them from reusing them), we can add the following line to the file:
password required pam_pwhistory.so remember=99 use_authok
In the example config
line, I’m using remember=99
, which (as you can probably guess) will cause our system to remember the last 99 passwords for each user and prevent them from using those passwords again. If you’ve configured a minimum password age earlier, for example, 5 days, it would take the user 495 days to cycle back to their original password if you take into account that the user changes their password once every 5 days, 99 times. That pretty much makes it impossible for the user to utilize their old passwords.
Another field worth mentioning within the /etc/pam.d/common-password
file is the section that reads difok=3
. This configuration mandates that at least three characters have to be different before the password is considered acceptable. Otherwise, the password would be deemed too similar to the old one and refused. You can change this value to whatever you like; the default is normally 5
but Ubuntu defaults it to 3
in their implementation of this config file. In addition, you’ll also see obscure
mentioned in the file as well, which prevents simple passwords from being used (such as common dictionary words and so on).
Setting a password policy is a great practice to increase the security of your server. However, it’s also important to not get carried away. In order to strike a balance between security and user frustration, the challenge is always to create enough restrictions to increase your security, while trying to minimize the frustration of your users. Of course, the mere mention of the word “password” to a typical user is enough to frustrate them, so you can’t please everyone. But in terms of overall system security, I’m sure your users will appreciate the fact that they can be reasonably sure that you as an administrator have taken the necessary precautions to keep their (and your company’s) data safe. When it comes down to it, use your best judgment.
Since we’re on the subject of security, we should also take a look at configuring sudo
itself, which we’ll take care of in the next section.
Configuring administrator access with sudo
By now, we’ve already used sudo
quite a few times in this book. At this point, you should already be aware of the fact that sudo
allows you to execute commands as if you were logged in as another user, with root
being the default. However, we haven’t had any formal discussion about it yet, nor have we discussed how to actually modify which of your user accounts are able to utilize sudo
.
On all Linux systems, you should protect your root
account with a strong password and limit it to being used by as few people as possible. On Ubuntu, the root
account is locked anyway, so unless you unlocked it by setting a password (or you’re using a version of Ubuntu supplied by a VPS provider), it cannot be used to log in to the system. Using sudo
is an alternative to logging in as root
to execute commands directly, so you can give your administrators access to perform tasks that require root
privileges with sudo
without actually giving them your root
password or unlocking the root
account. In fact, sudo
allows you to be a bit more granular. Using root
directly is basically all or nothing—if someone knows the root
password and the root
account is enabled, that person is not limited and can do whatever they want. With sudo
, that can also be true, but you can actually restrict some users to use only particular commands and therefore limit the scope of what they are able to do on the system. For example, you could give an admin access to install software updates but not allow them to reboot the server.
By default, members of the sudo
group are able to use sudo
without any restrictions. Basically, members of this group can do anything root
can do (which is everything). During installation, the user account you created was made a member of sudo
. To give additional users access to sudo
, all you would need to do is add them to the sudo
group:
sudo usermod -aG sudo <username>
Not all distributions utilize the sudo
group by default, or even automatically install sudo
. Other distributions require you to install sudo
manually and may use another group (such as wheel
) to govern access to sudo
.
But again, that gives those users access to everything, and that may or may not be what you want. To actually configure sudo
, we use the visudo
command. This command assists you with editing /etc/sudoers
, which is the configuration file that governs sudo
access. Although you can edit /etc/sudoers
yourself with a text editor, configuring sudo
in that way is strongly discouraged. The visudo
command checks to make sure your changes follow the correct syntax and helps prevent you from accidentally destroying the file. This is a very good approach, because if you did make any errors in the /etc/sudoers
file, you may wind up in a situation where no one is able to gain administrative control over the server. And while there are ways to recover from such a mistake, it’s certainly not a very pleasant situation to find yourself in! So, the takeaway here is never to edit the /etc/sudoers
file directly; always use visudo
to do so.
Here’s an example of the type of warning the visudo
command shows when you make a mistake:

Figure 2.13: The visudo command showing an error
If you do see this error, press e to return to edit the file, and then correct the mistake.
The way this works is when you run visudo
from your shell, you are brought into a text editor with the /etc/sudoers
file opened up. You can then make changes to the file and save it like you would any other text file. By default, Ubuntu opens up the nano
text editor when you use visudo
. With nano
, you can save changes using Ctrl + w, and you can exit the text editor with Ctrl + x.
So visudo
allows you to make changes to who is able to access sudo
. But how do you actually make these changes? Go ahead and scroll through the /etc/sudoers
file that visudo
opens and you should see a line similar to the following:
%sudo ALL=(ALL:ALL) ALL
This is the line of configuration that enables sudo
access to anyone who is a member of the sudo
group. You can change the group name to any that you’d like, for example, perhaps you’d like to create a group called admins
instead. If you do change this, make sure that you actually create that group and add yourself and your staff to be members of it before you edit the /etc/sudoers
file or log off; it would be rather embarrassing if you found yourself locked out of administrator access to the server.
Of course, you don’t have to enable access by group. You can actually call out a username instead. With the /etc/sudoers
file, groups are preceded by %
, while users are not. As an example of this, we also have the following line in the file:
root ALL=(ALL:ALL) ALL
Here, we’re calling out a username (in this case, root
), but the rest of the line is the same as the one I pointed out before. While you can certainly copy this line and paste it one or more times (substituting root
for a different username) to grant access to others, using the group approach is really the best way. It’s easier to add and remove users from a group (such as the sudo
group) than it is to use visudo
each time.
So, at this point, you’re probably wondering what the options on /etc/sudoers
configuration lines actually mean. So far, both examples used ALL=(ALL:ALL) All
. In order to fully understand sudo
, understanding the other fields is extremely important, so let’s go through them (using the root
line again as an example).
The first ALL
means that root
is able to use sudo
from any terminal. The second ALL
means that root
can use sudo
to impersonate any other user. The third ALL
means that root
can impersonate any other group. Finally, the last ALL
refers to what commands this user is able to use; in this case, any command they wish.
To help drive this home, I’ll give some additional examples. Here’s a hypothetical example:
charlie ALL=(ALL:ALL) /sbin/reboot,/sbin/shutdown
Here, we’re allowing user charlie
to execute the reboot
and shutdown
commands. If user charlie
tries to do something else (such as install a package), they will receive an error message:
Sorry, user charlie is not allowed to execute '/usr/bin/apt install tmux' as root on ubuntu.
However, if charlie
wants to use the reboot
or shutdown
commands on the server, they will be able to do so because we explicitly called out those commands while setting up this user’s sudo
access. We can limit this further by changing the first ALL
to a machine name, in this case, ubuntu
, to reference the host name of the server I’m using for my examples. I’ve also changed the command that charlie
is allowed to run:
charlie ubuntu=(ALL:ALL) /usr/bin/apt
It’s always a good idea to use full paths to commands when editing sudo
permissions, rather than the shortened versions. For example, we used /usr/bin/apt
here, instead of just apt
. This is important, as the user could create a script named apt
to do mischievous things that we normally wouldn’t allow them to do. By using the full path, we’re limiting the user to the binary stored at that path.
Now, charlie
is only able to use apt
. They can use apt update
, apt dist-upgrade
, and any other sub-command of apt
. But if they try to reboot the server, remove protected files, add users, or anything else we haven’t explicitly set, they will be prevented from doing so.
We have another problem, though. We’re allowing charlie
to impersonate other users. This may not be completely terrible given the context of installing packages (impersonating another user would be useless unless that user also has access to install packages), but it’s bad form to allow this unless we really need to. In this case, we could just remove the (ALL:ALL)
from the line altogether to prevent charlie
from using the -u
option of sudo
to run commands as other users:
charlie ubuntu= /usr/bin/apt
On the other hand, if we actually do want charlie
to be able to impersonate other users (but only specific users), we can call out the username and group that charlie
is allowed to act on behalf of by setting those values:
charlie ubuntu=(dscully:admins) ALL
In that example, charlie
is able to run commands on behalf of the user dscully
and the group admins
.
Of course, there is much more to sudo
than what I’ve mentioned in this section. Entire books could be written about sudo
(and have been), but 99% of what you will need for your daily management of this tool involves how to add access to users while being specific about what each user is able to do. As a best practice, use groups when you can (for example, you could have an apt
group, a reboot
group, and so on) and be as specific as you can regarding who is able to do what. This way, you’re not only able to keep the root
account private (or even better, disabled), but you also have more accountability on your servers.
Now that we’ve explored granting access to sudo
, we will next take a look at permissions, which give us even more control over what our users are able to access.
Setting permissions on files and directories
In this section, all the user management we’ve done in this chapter so far all comes together. We’ve learned how to add accounts, manage accounts, and secure them, but we haven’t actually done any work regarding managing the resources as far as who is able to access them. In this section, I’ll give you a brief overview of how permissions work in Ubuntu Server and then I’ll provide some examples for customizing them.
Viewing permissions
I’m sure by now that you understand how to list the contents of a directory with the ls
command. When it comes to viewing permissions, the -l
flag is especially handy, as the output that the long listing provides allows us to view the permissions of an object:
ls -l
The following are some example, hypothetical file listings:
-rw-rw-rw- 1 doctor 5 Jan 11 12:52 welcome
-rw-r--r-- 1 root root 665 Feb 19 profile
-rwxr-xr-x 1 dalek dalek 35125 Nov 7 exterminate
In each line, we see several fields of information. The first column is our permission string for the object (for example, -rw-r—r--
), which we’ll cover in more detail shortly. We also see the link count for the object (second column). Links are beyond the scope of this chapter but will be discussed in Chapter 5, Managing Files and Directories. Continuing on, the user that owns the file is displayed in the third column, the group that owns the file is in the fourth column, the size in bytes is in the fifth, the last date the file was modified is in the sixth, and finally there is the name of the file.
Keep in mind that depending on how your shell is configured, your output may look different and the fields may be in different places. For the sake of our discussion on permissions, what we’re really concerned with is the permissions string, as well as the owning user and group. In this case, we can see that the first file (named welcome
) is owned by a user named doctor
. The second file is named profile
and is owned by root
. Finally, we have a file named exterminate
owned by a user named dalek
.
With these files, we have the permission strings of -rw-rw-rw-
, -rw-r--r--
, and -rwxr-xr-x
respectively. If you haven’t worked with permissions before, these may seem strange, but it’s actually quite easy when you break them down. Each permission string can be broken down into four groups, as I’ll show you in the following table:
Object type |
User |
Group |
World |
- |
|
|
|
- |
|
|
|
- |
|
|
|
I’ve broken down each of the three example permission strings into four groups. Basically, I split them each at the first character and then again every third. The first section of a permission string is just one character. In each of these examples, it’s just a single hyphen. This refers to what type the object is. Is it a directory? A file? A link? In our case, each of these permission strings is a file, because the first positions of the permission strings are all hyphens. If the object were a directory, the first character would’ve been a d
instead of a -
. If the object were a link, this field would’ve been l
(lowercase L) instead.
In the next section, in the second column of each object, we have three characters, rw-
, rw-
, and rwx
respectively. This refers to the permissions that apply to the user that owns the file. For example, here is the first permission string again:
-rw-rw-rw- 1 doctor doctor 5 Jan 11 12:52 welcome
The third section of the preceding code output shows us that doctor
is the user that owns the file. Therefore, referring back to the table, the second column of the permission string (rw-
) applies specifically to the user doctor
. Moving on, the third column of permissions is also three characters; in this case, rw-
again. This section of the permissions string refers to the group that owns the file. In this case, the group is also named doctor
, as you can see in column four of the preceding code output. Finally, the last section of the permission string, visualized in the table (rw-
yet again, in this case), refers to world
, also known as other. This basically refers to anyone else other than the owning user and owning group. Therefore, literally everyone else gets at least rw-
permissions on the object.
Individually, r
stands for read and w
stands for write. Therefore, we can read the second column (rw-
), indicating that the user (doctor
) has access to read and write to this file. The third column (rw-
again) tells us the doctor
group also has read and write access to this file. The fourth column of the permission string is the same, so anyone else would also have read and write permissions to the file as well.
The third permission string I gave as an example looks a bit different. Here it is again:
-rwxr-xr-x 1 dalek dalek 35125 Nov 7 exterminate
Here, we see the x
attribute set. The x
attribute refers to the ability to execute the file as a script. So, with that in mind, we know that this file is likely a script and is executable by users, groups, and others. Given the filename of exterminate
, this is rather suspicious, and if it were a real file, we’d probably want to look into it.
If a permission is not set, it will simply be a single hyphen where there would normally be r
, w
, or x
. This is the same as indicating that a permission is disabled. Here are some examples:
rwx
: Object has read, write, and execute permissions set for this fieldr-x
: Object has read enabled, write disabled, and execute enabled for this fieldr--
: Object has read enabled, write disabled, and execute disabled for this field---
: Object has no permissions enabled for this field
Bringing this discussion all the way home, here are a few more permission strings:
-rw-r--r-- 1 sue accounting 35125 Nov 7 budget.txt
drwxr-x--- 1 bob sales 35125 Nov 7 annual_projects
For the first of these examples, we see that sue
is the owning user of budget.txt
and that this file is assigned an accounting group. This object is readable and writable by sue
and readable by everyone else (group
and world
). This is probably bad, considering this is a budget file and is probably confidential. We’ll change it later.
The annual_projects
object is a directory, which we can tell from the d
in the first column. This directory is owned by the bob
user and the sales
group. However, since this is a directory, each of the permission bits has different meanings. In the following two tables, I’ll outline the meanings of these bits for files and again for directories:
- Files:
Bit |
Meaning |
|
The file can be read |
|
The file can be written to |
|
The file can be executed as a program |
- Directories:
Bit |
Meaning |
|
The contents of the directory can be viewed |
|
The contents of the directory can be altered |
|
The user or group can use |
As you can see, permissions are read differently depending on their context: whether they apply to a file or a directory. In the example of the annual_projects
directory, bob
has rwx
permissions to the directory. This means that the user bob
can do everything (view the contents, add or remove contents, and use cd
to move the current directory of his shell into the directory). Regarding a group, members of the sales
group are able to view the contents of this directory and cd
into it. However, no one in the sales
group can add or remove items to or from the directory. On this object, other has no permissions set at all. This means that no one else can do anything at all with this object, not even view its contents.
Changing permissions
So, now we understand how to read permissions on files and directories. That’s great, but how do we alter them? As I mentioned earlier, the budget.txt
file is readable by everyone (other). This is not good because the file is confidential. To change permissions on an object, we will use the chmod
command. This command allows us to alter the permissions of files and directories in a few different ways.
First, we can simply remove read access from the sue
user’s budget file by removing the read bit from the other field. We can do that with the following example:
chmod o-r budget.txt
If we are currently not in the directory where the file resides, we need to give a full path:
chmod o-r /home/sue/budget.txt
If you’re using the chmod
command against files other than those you own yourself, you’ll need to use sudo
.
But either way, you probably get the idea. With this example, we’re removing the r
bit from other (o-r
). If we wanted to add this bit instead, we would simply use +
instead of -
. Here are some additional examples of chmod
in action:
chmod u+rw <filename>
: The object getsrw
added to theuser
columnchmod g+r <filename>
: The owning group is given read accesschmod o-rw <filename>
: Other is stripped of therw
bits
In addition, you can also use octal point values to manage and modify permissions. This is actually the most common method of altering permissions. I like to think of this as a scoring system. That’s not what it is, but it makes it a lot easier to understand to think of each type of access as having its own value. Basically, each of the permission bits (r
, w
, and x
) has its own octal equivalent, as follows:
- Read:
4
- Write:
2
- Execute:
1
With this style, there are only a few possibilities for numbers you can achieve when combining these octal values (each can only be used once). Therefore, we can get 0
, 1
, 2
, 3
, 4
, 5
, 6
, and 7
by adding (or not adding) these numbers in different combinations. Some of them you’ll almost never see, such as an object having write access but not read. For the most part, you’ll see 0
, 4
, 5
, 6
, and 7
used with chmod
most often. For example, if we add Read
and Write
, we get 6
. If we add Read
and Execute
, we get 5
. If we add all three, we get 7
. If we add no permissions, we get 0
. We repeat this for each column (User
, Group
, and Other
) to come up with a string of three numbers. Here are some examples:
600
:User
has read and write (4+2). No other permissions are set.This is the same as
-rw-------
.
740
:User
has read, write, and execute.Group
has read.Other
has nothing.This is the same as
-rwxr-----
.
770
: BothUser
andGroup
have full access (read, write, and execute).Other
has nothing.This is the same as
-rwxrwx---
.
777
: Everyone has everything.This is the same as
-rwxrwxrwx
.
Going back to chmod
, we can use this numbering system in practice:
chmod 600 filename.txt
chmod 740 filename.txt
chmod 770 filename.txt
Hopefully you get the idea. If you wanted to change the permissions of a directory, the -R
option may be helpful to you. This makes the changes recursive, meaning that you’ll not only make the changes to the directory but also to all files and directories underneath it in one shot:
chmod 770 -R mydir
While using -R
with chmod
can save you some time, it can also cause trouble if you have a mix of directories and files underneath the directory you’re changing permissions on. The previous example gives permissions 770
to mydir
and all of its contents. If there are files inside, they are now given executable permissions to the user and group, since 7
includes the execute bit (value of 1
). This may not be what you want. We can use the find
command to differentiate these. While find
is out of the scope of this chapter, it should be relatively simple to see what the following commands are doing and how they may be useful:
find /path/to/dir/ -type f -exec chmod 644 {} \;
find /path/to/dir/ -type d -exec chmod 755 {} \;
Basically, in the first example, the find
command is locating all files (-type f
) in /path/to/dir/
and everything it finds, it executes chmod 644
against. The second example is locating all directories in this same path and changing them all to permission 755
. The find
command isn’t covered in detail here because it easily deserves a chapter of its own, but I’m including it here because hopefully these examples are useful and will be handy for you to include in your own list of useful commands.
Changing the ownership of objects
Finally, we’ll need to know how to change the ownership of files and directories. It’s often the case that a particular user needs to gain access to an object, or perhaps we need to change the owning group as well. We can change user and group ownership of a file or directory with the chown
command. As an example, if we wanted to change the owner of a file to sue
, we could do the following:
sudo chown sue myfile.txt
In the case of a directory, we can also use the -R
flag to change the ownership of the directory itself, as well as all the files and directories it may contain:
sudo chown -R sue mydir
If we would like to change the group assignment to the object, we would follow the following syntax:
sudo chown sue:sales myfile.txt
Notice the colon separating the user and the group. With that command, we established that we would like the sue
user and the sales
group to own this resource. Again, we could use -R
if the object were a directory and we wanted to make the changes recursive.
Another command worth knowing is the chgrp
command, which allows you to directly change the group ownership of a file. To use it, you can execute the chgrp
command along with the group you’d like to own the file, followed by the filename. For example, our previous chown
command can be simplified to the following, since we were only modifying the group assignment of that file:
sudo chgrp sales myfile.txt
Just like the chown
command, we can use the -R
option with chgrp
to make our changes recursively, in the case of a directory.
Well, there you have it. You should now be able to manage permissions of the files and directories on your server. If you haven’t worked through permissions on a Linux system before, it may take a few tries before you get the hang of it. The best thing for you to do is to practice. Create some files and directories (as well as users) and manage their permissions. Try to remove a user’s access to a resource and then try to access that resource as that user anyway and see what errors you get. Fix those errors and work through more examples. With practice, you should be able to get a handle on this very quickly.
Summary
In Linux administration and related fields, managing users and permissions is something you’ll find yourself doing quite a bit. New users will join your organization, while others will leave, so this is something that will become ingrained in your mental toolset. Even if you’re the only person using your servers, you’ll find yourself managing permissions for applications as well, given the fact that processes cannot function if they don’t have access to their required resources.
In this chapter, we took a lengthy dive into managing users, groups, and permissions. We worked through creating and removing users, assigning permissions, and managing administrative access with sudo
. Practice these concepts on your server. When you get the hang of it, I’ll see you in our next chapter, where we’ll discuss all things related to package management. It’s going to be epic.
Relevant videos
- Linux Crash Course – Managing Users (LearnLinuxTV): https://linux.video/lcc-users
- Linux Crash Course – Understanding File & Directory Permissions (LearnLinuxTV): https://linux.video/lcc-perm
- Linux Crash Course – usermod (LearnLinuxTV): https://linux.video/lcc-usermod
- Linux Crash Course – sudo (LearnLinuxTV): https://linux.video/lcc-sudo
- Linux Crash Course – User Account & Password Expiration (LearnLinuxTV): https://linux.video/lcc-userexp
- Linux Crash Course – Managing Groups (LearnLinuxTV): https://linux.video/lcc-groups
Further reading
- File permissions (Ubuntu community wiki): https://learnlinux.link/ubuntu-perms
- User management (Ubuntu documentation): https://learnlinux.link/sec-users
Join our community on Discord
Join our community’s Discord space for discussions with the author and other readers: