Shells are perhaps the main interface for Linux systems. Even without a graphical user interface (GUI), the shell facilitates full system control. Because of this and other reasons, our choice of default shell can be very important.
In this tutorial, we talk about an issue we may encounter when attempting to change the default shell via chsh. First, we briefly refresh our knowledge about default shell changes. After that, we understand how one of the ways to do that is influenced by a fundamental Linux security mechanism. Finally, we delve into the exact issue this mechanism can cause and ways to deal with it.
2. Change Default Shell
The default shell is the process that runs right after a user authenticates and logs in.
To begin with, let’s check the current default shell of a user via /etc/passwd:
$ cat /etc/passwd
In this case, user fisher has a default shell of /bin/bash. Naturally, fisher probably prefers the fish shell instead.
To facilitate that desire, we can use the –shell option of chsh and set a new default shell:
$ chsh --shell /usr/bin/fish fisher
Here, we set /usr/bin/fish as the default for user fisher.
Now, we can confirm the switch by checking the contents of /etc/passwd again:
$ cat /etc/passwd
In this case, we see that the fisher user now employs /usr/bin/fish as their default shell.
To change the default shell of the current user, we just omit the username at the end of the command:
$ chsh --shell /usr/bin/fish
However, we may encounter an issue when running either of the above chsh commands.
3. chsh PAM Restrictions
Since a shell can take away or grant certain access, the use of chsh is mandated by a Pluggable Authentication Module (PAM).
As expected, the PAM settings for chsh are at /etc/pam.d/chsh:
$ cat /etc/pam.d/chsh
# The PAM configuration file for the Shadow `chsh' service
# This will not allow a user to change their shell unless
# their current one is listed in /etc/shells. This keeps
# accounts with special shells from changing them.
auth required pam_shells.so
# This allows root to change user shell without being
# prompted for a password
auth sufficient pam_rootok.so
# The standard Unix authentication modules, used with
# NIS (man nsswitch) as well as normal /etc/passwd and
# /etc/shadow entries.
This fairly short configuration file contains two important lines:
- auth required pam_shells.so verifies that the current shell of the authenticated user is listed in /etc/shells via the pam_shells.so module
- auth sufficient pam_rootok.so checks whether the current user is root and stops further checks if so due to the sufficiency of the condition
In fact, the rest of the file only runs for non-root users to verify their account privileges and setup the session.
4. chsh Password Prompt and PAM: Authentication failure
For this section, let’s assume we work as root directly or via sudo. We indicate this with the # prompt.
4.1. Attempt Shell Change
First, we try to change the shell of fisher back to /bin/bash:
$ chsh --shell /bin/bash fisher
Unexpectedly, we get a Password: prompt.
Upon entering any password, regardless of whether it’s correct or not, we get a message:
# chsh --shell /bin/bash fisher
chsh: PAM: Authentication failure
Notably, this happens even when using sudo.
At this point, let’s take a step back and analyze the PAM conditions for chsh relative to our context.
4.2. PAM Check Analysis
Once we issue chsh as root, we can be certain that the second PAM condition for the command, pam_rootok.so passes by definition.
However, the first line of /etc/pam.d/chsh checks whether the shell of the user that runs chsh is in /etc/shells.
So, let’s check /etc/passwd and see what the shell of our current root user is:
# cat /etc/passwd
Seemingly, root uses the fish shell. Let’s map that to the /etc/shells file:
# cat /etc/shells
# /etc/shells: valid login shells
Critically, /usr/bin/fish is a shell, but just fish isn’t, according to /etc/shells. The same applies to /bin/bash and /usr/bin/bash on one hand and bash, on the other, as well as others in the list. In other words, the shell executable isn’t a valid setting in /etc/passwd.
In short, the PAM library calls pam_shells.so, which rejects fish as a valid shell.
Although a user having an invalid default shell is fairly uncommon, the ways this can happen are many.
For example, assuming root has a valid default shell of /bin/bash, we can issue a chsh to change that to fish, since no further checks are done for the new shell:
# chsh --shell badshell
At this point, badshell is the new entry in /etc/passwd:
# cat /etc/passwd
Of course, we can also do this directly in the /etc/passwd file. In any case, from the moment of the change, we won’t be able to use root for changing shells.
In fact, this is precisely the reason why logging in as the root user directly is a bad practice: it allows too much control over the system, including ways to lock ourselves out.
4.4. Solutions and Workarounds
Naturally, we can always skip chsh and just edit /etc/passwd directly.
Yet, once we understand the problem, there are different ways to solve it for chsh:
- temporarily comment out auth required pam_shells.so from /etc/pam.d/chsh, so the /etc/shells check isn’t done
- permanently or temporarily switch the first two uncommented lines in /etc/pam.d/chsh, so root doesn’t require the /etc/shells check
- manually change the default root shell in /etc/passwd, so the /etc/shells check passes
- temporarily add the current default root shell to /etc/shells, so the /etc/shells check passes
After we apply any workaround, we can set the default root shell to a valid one and restore the changes. However, the second option might make sense in general, since root is usually an exception in many situations.
In this article, we talked about shell changes and restrictions imposed by the PAM system on chsh.
In conclusion, despite the default settings and potential consequences from them, we can work around PAM problems by making relevant changes to the chsh configuration file.