73

I have often heard it recommended that a user account should be disabled by setting its shell to /bin/false. But, on my existing Linux systems, I see that a great number of existing accounts (all of them service accounts) have a shell of /sbin/nologin instead.

I see from the man page that /sbin/nologin prints a message to the user saying the account is disabled, and then exits. Presumably /bin/false would not print anything.

I also see that /sbin/nologin is listed in /etc/shells, while /bin/false is not.

The man page says that FTP will disable access for users with a shell not listed in /etc/shells and implies that other programs may do the same. Does that mean that somebody could FTP in with an account that has /sbin/nologin as its shell?

What is the difference here? Which one of these should I use to disable a user account, and in what circumstances? What other effects does a listing in /etc/shells have?

Michael Hampton
  • 237,123
  • 42
  • 477
  • 940

3 Answers3

75

/bin/false is a utility program, companion to /bin/true, which is useful in some abstract sense to ensure that unix is feature-complete. However, emergent purposes for these programs have been found; consider the BASH statement /some/program || /bin/true, which will always boolean-evaluate to true ($? = 0) no matter the return of /some/program.

An emergent use of /bin/false, as you identified, is as a null shell for users not allowed to log in. The system in this case will behave exactly as though the shell failed to run.

POSIX (though I may be wrong and it may the the SUS) constrains both these commands to do exactly nothing other than return the appropriate boolean value.

/sbin/nologin is a BSD utility which has similar behaviour to /bin/false (returns boolean false), but prints output as well, as /bin/false is prohibited from doing. This is supposed to help the user understand what happened, though in practice many terminal emulators will simply close when the shell terminates, rendering the message all but unreadable anyway in some cases.

There is little purpose to listing /sbin/nologin in /etc/shells. The standard effect of /etc/shells is to list the programs permissible for use with chsh when users are changing their own shell (and there is no credible reason to change your own shell to /sbin/nologin). The superuser can change anyone's shell to anything. However, you may want to list both /sbin/nologin and /bin/false in /etc/rsh, which will prohibit users with these shells from changing their shell using chsh in the unfortunate event that they get a shell.

FTP daemons may disallow access to users with a shell not in /etc/shells, or they may use any other logic they wish. Running FTP is to be avoided in any case because sftp (which provides similar functionality) is similar but secure. Some sites use /sbin/nologin to disable shell access while allowing sftp access by putting it in /etc/shells. This may open a backdoor if the user is allowed to create cronjobs.

In either case, scp will not operate with an invalid shell. scponly can be used as a shell in this instance.

Additionally, the choice of shell affects the operation of su - (AKA su -l). Particularly, the output of /sbin/nologin will be printed to stdout if it is the shell; this cannot be the case with /bin/false. In either case commands run with su -cl will fail.

Finally, the answer:

To disable an account, you should do three things.

  1. Set the shell to /sbin/nologin
  2. Set the password field in /etc/passwd to the appropriate locked value for your UNIX (! on Linux, but *LOCKED* on FreeBSD). This prevents SSH login with keys unless UsePAM yes is set in the sshd_config.
  3. Set the account expiration date to the distant past (e.g., usermod --expiredate 1). This step will prevent SSH login with any method if PAM is used to process the login.

If it's a service account, it's enough to make sure that it has no SSH authorized keys in its home directory and the first two steps above. If you're worried someone might get an SSH certificate for it or something, you could always list your service accounts and groups in DenyUsers and DenyGroups in sshd_config.

Falcon Momot
  • 24,975
  • 13
  • 61
  • 92
  • 9
    While this answer summarizes perfectly the different options (and answers the question), I felt the need to point to a useful resource for this use case, which is available at least in the stock Debian repositories, in the `titantools` package: `noshell`. This pseudo-shell provides auditing capabilities, logging to syslog attempts to use accounts with `noshell` as its shell, while still disallowing access. – dawud Jun 28 '13 at 08:13
  • 1
    It is by no means apocryphal, but is in fact quite common amongst sysadmins of a certain vintage (cough), to use `/bin/false` as a login shell for people who shouldn't log in. – MadHatter Jun 28 '13 at 08:23
  • 2
    Apocryphal in the sense that it isn't the original intended use. I didn't say anachronistic; I see it every day :) – Falcon Momot Jun 28 '13 at 08:24
  • It seems that `passwd -l user` also works, by adding in the `!`. This appears to be the best method for disabling a user account. – Michael Hampton Jun 28 '13 at 16:18
  • That it is, but the passwd manpage suggests yet another way and warns of inadequacy. This account disabling thing is a neverending rabbit hole, it seems :) – Falcon Momot Jun 28 '13 at 20:49
  • @FalconMomot "apocryphal" means something that is not likely to be true or is of questionable validity, I don't think that's what you meant :) – KutuluMike Jun 28 '13 at 22:02
  • You're right - I meant emergent. – Falcon Momot Jul 23 '13 at 06:14
  • 1
    Disabling the account by invalid password does not work too well with ssh. If the user had managed to previously set up public key authentication he might be able to get in anyway. – joshudson Sep 12 '14 at 19:24
  • 3
    sshd is documented to check that accounts that are locked in certain ways (password hashes beginning with ! are mentioned specifically) even with pubkey auth. – Falcon Momot Sep 13 '14 at 05:14
  • Falcon Momot, this is not true: default sshd setting will allow to login with key even for locked users (password hash begins with "!") – Vanav Jun 21 '22 at 00:52
  • Only if PAM is used! But I've updated the answer with that info. – Falcon Momot Jul 27 '22 at 04:01
13

After doing some research on this, the method you use depends on what you have to lock out . If a user logs in with this set to the shell then they will get a message displayed to the effect of This account is currently unavailable. Note that you can change this by creating the file /etc/nologin.txt at least on RHEL derivatives.

As you know /bin/false is not a shell. They way it works is that it returns false which logs out immediately after the binary exits. Note that /bin/true would achieve the same effect.

Regarding your FTP question: Yes, you are correct in that having the shell set to /sbin/nologin will allow users to login to FTP while /bin/false or /bin/true will completely prevent the user from logging into any service.

Therefore, /bin/false or /bin/true is best to prevent a user from logging into any service, while /sbin/nologin will still allow users to log into services other than SSH or local console while providing feedback to the user that the account is inactive and is best used when only SSH/local console need to be locked out.

Jacob
  • 9,114
  • 4
  • 44
  • 56
3

Um, did anyone try to prove that /bin/false would disallow FTP access?

I just changed my user's shell to /bin/false, and was able to FTP in just fine.

I use /dev/null to completely lock out the user (well, except email, they can still POP3).

Jim Dunn
  • 41
  • 1
  • Did you have it in `/etc/shells`? How is your FTP server configured? – Michael Hampton Sep 01 '13 at 02:27
  • there is no rule saying that a user need a shell to log into an FTP-server. – Petter H Sep 01 '13 at 07:49
  • 2
    It will disallow it on some FTP daemons, and not others. There is quite a lot of variance in functionality between the various ones. The classical implementation will disallow access to anyone who hasn't a shell, but that doesn't mean all implementations have to. – Falcon Momot Sep 03 '13 at 09:38